Merge branch 'v1.8'

This commit is contained in:
chenjianxing 2021-03-30 13:06:03 +08:00
commit c93a4913a7
71 changed files with 1208 additions and 1080 deletions

3
Jenkinsfile vendored
View File

@ -13,6 +13,9 @@ pipeline {
stage('Build/Test') {
steps {
configFileProvider([configFile(fileId: 'metersphere-maven', targetLocation: 'settings.xml')]) {
sh "cd frontend"
sh "yarn install"
sh "cd .."
sh "mvn clean package --settings ./settings.xml"
}
}

View File

@ -276,18 +276,11 @@
<artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>
<!-- swagger2 解析 -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-parser</artifactId>
<version>1.0.51</version>
</dependency>
<!-- swagger3 解析 最新版本会有swagger-core版本冲突 -->
<!-- swagger 解析 -->
<dependency>
<groupId>io.swagger.parser.v3</groupId>
<artifactId>swagger-parser</artifactId>
<version>2.0.18</version>
<version>2.0.22</version>
</dependency>
<!-- 执行 js 代码依赖 -->

View File

@ -29,6 +29,7 @@ public class EsbDataStruct {
private boolean required;
private String description;
private List<EsbDataStruct> children;
private String status = "";
public void init(){
this.uuid = UUID.randomUUID().toString();
@ -127,6 +128,9 @@ public class EsbDataStruct {
if (element != null) {
if (this.children == null || this.children.isEmpty()) {
if(this.value == null ){
this.value = "";
}
element.addText(this.value);
} else {
for (EsbDataStruct child : children) {

View File

@ -58,14 +58,16 @@ public class MsDefinitionParser extends MsAbstractParser<ApiDefinitionImport> {
private ApiDefinitionImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) {
ApiDefinitionImport apiDefinitionImport = JSON.parseObject(testStr, ApiDefinitionImport.class);
Map<String, List<ApiTestCaseWithBLOBs>> caseMap = new HashMap<>();
apiDefinitionImport.getCases().forEach(item -> {
List<ApiTestCaseWithBLOBs> caseList = caseMap.get(item.getApiDefinitionId());
if (caseList == null) {
caseList = new ArrayList<>();
caseMap.put(item.getApiDefinitionId(), caseList);
}
caseList.add(item);
});
if (apiDefinitionImport.getCases() != null) {
apiDefinitionImport.getCases().forEach(item -> {
List<ApiTestCaseWithBLOBs> caseList = caseMap.get(item.getApiDefinitionId());
if (caseList == null) {
caseList = new ArrayList<>();
caseMap.put(item.getApiDefinitionId(), caseList);
}
caseList.add(item);
});
}
apiDefinitionImport.getData().forEach(apiDefinition -> {
parseApiDefinition(apiDefinition, importRequest, caseMap);
});

View File

@ -70,8 +70,9 @@ public class Swagger2Parser extends SwaggerAbstractParser {
parseParameters(operation, request);
addBodyHeader(request);
if (StringUtils.isNotBlank(basePath)) {
apiDefinition.setPath(basePath + apiDefinition.getPath());
request.setPath(basePath + request.getPath());
String pathStr = basePath + apiDefinition.getPath().replaceAll("//","/");
apiDefinition.setPath(pathStr);
request.setPath(pathStr);
}
apiDefinition.setRequest(JSON.toJSONString(request));
apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation, operation.getResponses())));
@ -148,6 +149,14 @@ public class Swagger2Parser extends SwaggerAbstractParser {
return getBodyType(contentType);
}
private String getResponseBodyType(Operation operation) {
if (CollectionUtils.isEmpty(operation.getProduces())) {
return Body.JSON;
}
String contentType = operation.getProduces().get(0);
return getBodyType(contentType);
}
private void parsePathParameters(Parameter parameter, List<KeyValue> rests) {
PathParameter pathParameter = (PathParameter) parameter;
rests.add(new KeyValue(pathParameter.getName(), "", getDefaultStringValue(parameter.getDescription())));
@ -174,14 +183,17 @@ public class Swagger2Parser extends SwaggerAbstractParser {
msResponse.getBody().setKvs(new ArrayList<>());
msResponse.setHeaders(new ArrayList<>());
msResponse.setType(RequestType.HTTP);
msResponse.getBody().setType(getBodyType(operation));
msResponse.getBody().setType(getResponseBodyType(operation));
// todo 状态码要调整
msResponse.setStatusCode(new ArrayList<>());
if (responses != null) {
if (responses != null && responses.size() > 0) {
responses.forEach((responseCode, response) -> {
msResponse.getStatusCode().add(new KeyValue(responseCode, responseCode));
String body = parseSchema(response.getResponseSchema());
if (StringUtils.isNotBlank(body)) {
msResponse.getBody().setRaw(body);
}
parseResponseHeader(response, msResponse.getHeaders());
parseResponseBodyParameters(response, msResponse.getBody());
});
}
return msResponse;
@ -196,10 +208,6 @@ public class Swagger2Parser extends SwaggerAbstractParser {
}
}
private void parseResponseBodyParameters(Response response, Body body) {
body.setRaw(parseSchema(response.getResponseSchema()));
}
private void parseRequestBodyParameters(Parameter parameter, Body body) {
BodyParameter bodyParameter = (BodyParameter) parameter;
body.setRaw(parseSchema(bodyParameter.getSchema()));

View File

@ -89,7 +89,6 @@ public class MsScenario extends MsTestElement {
JSONObject element = JSON.parseObject(scenario.getScenarioDefinition());
hashTree = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
});
OldVersionUtil.transferHashTree(hashTree);
// 场景变量
if (StringUtils.isNotEmpty(element.getString("variables"))) {
LinkedList<ScenarioVariable> variables = mapper.readValue(element.getString("variables"),
@ -114,23 +113,26 @@ public class MsScenario extends MsTestElement {
// 设置共享cookie
config.setEnableCookieShare(enableCookieShare);
Map<String, EnvironmentConfig> envConfig = new HashMap<>(16);
// 兼容历史数据
if (environmentMap == null || environmentMap.isEmpty()) {
environmentMap = new HashMap<>(16);
if (StringUtils.isNotBlank(environmentId)) {
environmentMap.put(SessionUtils.getCurrentProjectId(), environmentId);
}
}
if (environmentMap != null && !environmentMap.isEmpty()) {
environmentMap.keySet().forEach(projectId -> {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentMap.get(projectId));
if (environment != null && environment.getConfig() != null) {
EnvironmentConfig env = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
envConfig.put(projectId, env);
if (config.getConfig() == null) {
// 兼容历史数据
if (this.environmentMap == null || this.environmentMap.isEmpty()) {
this.environmentMap = new HashMap<>(16);
if (StringUtils.isNotBlank(environmentId)) {
// 兼容1.8之前 没有environmentMap但有environmentId的数据
this.environmentMap.put("historyProjectID", environmentId);
}
});
config.setConfig(envConfig);
}
if (this.environmentMap != null && !this.environmentMap.isEmpty()) {
this.environmentMap.keySet().forEach(projectId -> {
ApiTestEnvironmentService environmentService = CommonBeanFactory.getBean(ApiTestEnvironmentService.class);
ApiTestEnvironmentWithBLOBs environment = environmentService.get(this.environmentMap.get(projectId));
if (environment != null && environment.getConfig() != null) {
EnvironmentConfig env = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
envConfig.put(projectId, env);
}
});
config.setConfig(envConfig);
}
}
if (CollectionUtils.isNotEmpty(this.getVariables())) {
config.setVariables(this.variables);

View File

@ -163,7 +163,6 @@ public abstract class MsTestElement {
element = mapper.readValue(apiDefinition.getRequest(), new TypeReference<MsTestElement>() {
});
hashTree.add(element);
OldVersionUtil.transferHashTree(hashTree);
}
} catch (Exception ex) {
ex.printStackTrace();

View File

@ -129,6 +129,11 @@ public class MsHTTPSamplerProxy extends MsTestElement {
config.setConfig(getEnvironmentConfig(useEnvironment));
}
// 1.8 之前历史数据
if(StringUtils.isEmpty(this.getProjectId()) && config.getConfig()!= null && !config.getConfig().isEmpty()){
this.setProjectId("historyProjectID");
}
// 添加环境中的公共变量
Arguments arguments = this.addArguments(config);
if (arguments != null) {

View File

@ -2,6 +2,7 @@ package io.metersphere.api.dto.definition.request.sampler;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import io.metersphere.api.dto.automation.EsbDataStruct;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.ParameterConfig;
import io.metersphere.api.dto.definition.request.processors.pre.MsJSR223PreProcessor;
@ -70,6 +71,12 @@ public class MsTCPSampler extends MsTestElement {
@JSONField(ordinal = 39)
private String projectId;
/**
* 新加两个参数场景保存/修改时需要的参数不会传递JMeter只是用于最后的保留
*/
private List<EsbDataStruct> esbDataStruct;
private List<EsbDataStruct> backEsbDataStruct;
@Override
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
// 非导出操作且不是启用状态则跳过执行

View File

@ -361,7 +361,8 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
requestResult.addPassAssertions();
}
//xpath 提取错误会添加断言错误
if (StringUtils.isBlank(responseAssertionResult.getMessage()) || !responseAssertionResult.getName().endsWith("XPath2Extractor")) {
if (StringUtils.isBlank(responseAssertionResult.getMessage()) ||
(StringUtils.isNotBlank(responseAssertionResult.getName()) && !responseAssertionResult.getName().endsWith("XPath2Extractor"))) {
responseResult.getAssertions().add(responseAssertionResult);
}
}

View File

@ -90,6 +90,8 @@ public class ApiAutomationService {
@Resource
@Lazy
private TestPlanScenarioCaseService testPlanScenarioCaseService;
@Resource
private EsbApiParamService esbApiParamService;
public List<ApiScenarioDTO> list(ApiScenarioRequest request) {
request = this.initRequest(request, true, true);
@ -184,6 +186,9 @@ public class ApiAutomationService {
scenario.setCreateTime(System.currentTimeMillis());
scenario.setNum(getNextNum(request.getProjectId()));
//检查场景的请求步骤如果含有ESB请求步骤的话要做参数计算处理
esbApiParamService.checkScenarioRequests(request);
apiScenarioMapper.insert(scenario);
List<String> bodyUploadIds = request.getBodyUploadIds();
@ -205,6 +210,9 @@ public class ApiAutomationService {
List<String> bodyUploadIds = request.getBodyUploadIds();
FileUtils.createBodyFiles(bodyUploadIds, bodyFiles);
//检查场景的请求步骤如果含有ESB请求步骤的话要做参数计算处理
esbApiParamService.checkScenarioRequests(request);
final ApiScenarioWithBLOBs scenario = buildSaveScenario(request);
apiScenarioMapper.updateByPrimaryKeySelective(scenario);
extScheduleMapper.updateNameByResourceID(request.getId(), request.getName());// 修改场景name同步到修改首页定时任务
@ -234,6 +242,10 @@ public class ApiAutomationService {
} else {
scenario.setUserId(request.getUserId());
}
if (StringUtils.isEmpty(request.getApiScenarioModuleId()) || StringUtils.isEmpty(request.getModulePath())) {
scenario.setApiScenarioModuleId("default-module");
scenario.setModulePath("/默认模块");
}
return scenario;
}

View File

@ -3,10 +3,7 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.datacount.ExecutedCaseInfoResult;
import io.metersphere.api.jmeter.TestResult;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiDefinitionExecResultExample;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
import io.metersphere.base.domain.TestPlanApiCase;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.ApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ApiTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
@ -43,7 +40,7 @@ public class ApiDefinitionExecResultService {
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
private TestCaseReviewApiCaseService testCaseReviewApiCaseService;
private TestCaseReviewApiCaseService testCaseReviewApiCaseService;
@Resource
SqlSessionFactory sqlSessionFactory;
@ -73,6 +70,13 @@ public class ApiDefinitionExecResultService {
testCaseReviewApiCaseService.setExecResult(item.getName(), status);
}
// 清空上次执行结果的内容只保留当前最新一条内容
ApiDefinitionExecResult prevResult = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(item.getName(), type);
if (prevResult != null) {
prevResult.setContent(null);
definitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
}
// 更新用例最后执行结果
ApiTestCaseWithBLOBs apiTestCaseWithBLOBs = new ApiTestCaseWithBLOBs();
apiTestCaseWithBLOBs.setId(saveResult.getResourceId());
@ -94,7 +98,7 @@ public class ApiDefinitionExecResultService {
*/
public void saveApiResultByScheduleTask(TestResult result, String type) {
String saveResultType = type;
if(StringUtils.equalsAny(ApiRunMode.SCHEDULE_API_PLAN.name(),saveResultType)){
if (StringUtils.equalsAny(ApiRunMode.SCHEDULE_API_PLAN.name(), saveResultType)) {
saveResultType = ApiRunMode.API_PLAN.name();
}
@ -127,6 +131,12 @@ public class ApiDefinitionExecResultService {
}
saveResult.setUserId(userID);
// 前一条数据内容清空
ApiDefinitionExecResult prevResult = extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(item.getName(), finalSaveResultType);
if (prevResult != null) {
prevResult.setContent(null);
apiDefinitionExecResultMapper.updateByPrimaryKeyWithBLOBs(prevResult);
}
apiDefinitionExecResultMapper.insert(saveResult);
});
}

View File

@ -262,7 +262,10 @@ public class ApiDefinitionService {
test.setEnvironmentId(request.getEnvironmentId());
test.setUserId(request.getUserId());
test.setTags(request.getTags());
if (StringUtils.isEmpty(request.getModulePath()) || StringUtils.isEmpty(request.getModuleId())) {
test.setModulePath("/默认模块");
test.setModuleId("default-module");
}
apiDefinitionMapper.updateByPrimaryKeySelective(test);
return test;
}
@ -279,7 +282,6 @@ public class ApiDefinitionService {
test.setProtocol(request.getProtocol());
test.setMethod(request.getMethod());
test.setPath(request.getPath());
test.setModuleId(request.getModuleId());
test.setProjectId(request.getProjectId());
request.getRequest().setId(request.getId());
test.setRequest(JSONObject.toJSONString(request.getRequest()));
@ -287,6 +289,11 @@ public class ApiDefinitionService {
test.setUpdateTime(System.currentTimeMillis());
test.setStatus(APITestStatus.Underway.name());
test.setModulePath(request.getModulePath());
test.setModuleId(request.getModuleId());
if (StringUtils.isEmpty(request.getModulePath()) || StringUtils.isEmpty(request.getModuleId())) {
test.setModulePath("/默认模块");
test.setModuleId("default-module");
}
test.setResponse(JSONObject.toJSONString(request.getResponse()));
test.setEnvironmentId(request.getEnvironmentId());
test.setNum(getNextNum(request.getProjectId()));
@ -344,13 +351,13 @@ public class ApiDefinitionService {
private void _importCreate(List<ApiDefinition> sameRequest, ApiDefinitionMapper batchMapper, ApiDefinitionWithBLOBs apiDefinition,
ApiTestCaseMapper apiTestCaseMapper, ApiTestImportRequest apiTestImportRequest, List<ApiTestCaseWithBLOBs> cases) {
if (CollectionUtils.isEmpty(sameRequest)) {
if(StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(),RequestType.HTTP)){
if (StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(), RequestType.HTTP)) {
String request = setImportHashTree(apiDefinition);
batchMapper.insert(apiDefinition);
apiDefinition.setRequest(request);
importApiCase(apiDefinition, apiTestCaseMapper, apiTestImportRequest, true);
}else{
if(StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(),RequestType.TCP)){
} else {
if (StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(), RequestType.TCP)) {
String request = setImportTCPHashTree(apiDefinition);
}
batchMapper.insert(apiDefinition);
@ -358,7 +365,7 @@ public class ApiDefinitionService {
} else {
String originId = apiDefinition.getId();
if(StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(),RequestType.HTTP)){
if (StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(), RequestType.HTTP)) {
//如果存在则修改
apiDefinition.setId(sameRequest.get(0).getId());
String request = setImportHashTree(apiDefinition);
@ -373,9 +380,9 @@ public class ApiDefinitionService {
}
});
}
}else {
} else {
apiDefinition.setId(sameRequest.get(0).getId());
if(StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(),RequestType.TCP)){
if (StringUtils.equalsAnyIgnoreCase(apiDefinition.getProtocol(), RequestType.TCP)) {
String request = setImportTCPHashTree(apiDefinition);
}
apiDefinitionMapper.updateByPrimaryKeyWithBLOBs(apiDefinition);
@ -392,6 +399,7 @@ public class ApiDefinitionService {
apiDefinition.setRequest(JSONObject.toJSONString(msHTTPSamplerProxy));
return request;
}
private String setImportTCPHashTree(ApiDefinitionWithBLOBs apiDefinition) {
String request = apiDefinition.getRequest();
MsTCPSampler tcpSampler = JSONObject.parseObject(request, MsTCPSampler.class);
@ -411,7 +419,7 @@ public class ApiDefinitionService {
if (CollectionUtils.isNotEmpty(cases)) {
int batchCount = 0;
cases.forEach(item -> {
if(!existCaseName.contains(item.getName())) {
if (!existCaseName.contains(item.getName())) {
item.setId(UUID.randomUUID().toString());
item.setCreateTime(System.currentTimeMillis());
item.setUpdateTime(System.currentTimeMillis());
@ -509,7 +517,7 @@ public class ApiDefinitionService {
}
public void addResult(TestResult res) {
if (!res.getScenarios().isEmpty() && !res.getScenarios().get(0).getRequestResults().isEmpty()) {
if (res != null && CollectionUtils.isNotEmpty(res.getScenarios()) && res.getScenarios().get(0) != null && CollectionUtils.isNotEmpty(res.getScenarios().get(0).getRequestResults())) {
RequestResult result = res.getScenarios().get(0).getRequestResults().get(0);
if (result.getName().indexOf("<->") != -1) {
result.setName(result.getName().substring(0, result.getName().indexOf("<->")));
@ -596,21 +604,25 @@ public class ApiDefinitionService {
}
for (int i = 0; i < data.size(); i++) {
ApiDefinitionWithBLOBs item = data.get(i);
if (StringUtils.isEmpty(item.getModuleId()) || StringUtils.isEmpty(item.getModulePath())) {
item.setModuleId("default-module");
item.setModulePath("/默认模块");
}
if (item.getName().length() > 255) {
item.setName(item.getName().substring(0, 255));
}
item.setNum(num++);
//如果EsbData需要存储,则需要进行接口是否更新的判断
if(apiImport.getEsbApiParamsMap()!= null){
if (apiImport.getEsbApiParamsMap() != null) {
String apiId = item.getId();
EsbApiParamsWithBLOBs model = apiImport.getEsbApiParamsMap().get(apiId);
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases());
if(model!=null){
if (model != null) {
apiImport.getEsbApiParamsMap().remove(apiId);
model.setResourceId(item.getId());
apiImport.getEsbApiParamsMap().put(item.getId(),model);
apiImport.getEsbApiParamsMap().put(item.getId(), model);
}
}else {
} else {
importCreate(item, batchMapper, apiTestCaseMapper, request, apiImport.getCases());
}
if (i % 300 == 0) {
@ -618,15 +630,15 @@ public class ApiDefinitionService {
}
}
//判断EsbData是否需要存储
if(apiImport.getEsbApiParamsMap()!= null && apiImport.getEsbApiParamsMap().size() > 0){
if (apiImport.getEsbApiParamsMap() != null && apiImport.getEsbApiParamsMap().size() > 0) {
EsbApiParamsMapper esbApiParamsMapper = sqlSession.getMapper(EsbApiParamsMapper.class);
for (EsbApiParamsWithBLOBs model : apiImport.getEsbApiParamsMap().values()) {
EsbApiParamsExample example = new EsbApiParamsExample();
example.createCriteria().andResourceIdEqualTo(model.getResourceId());
List<EsbApiParamsWithBLOBs> exiteModelList = esbApiParamsMapper.selectByExampleWithBLOBs(example);
if(exiteModelList.isEmpty()){
if (exiteModelList.isEmpty()) {
esbApiParamsMapper.insert(model);
}else{
} else {
model.setId(exiteModelList.get(0).getId());
esbApiParamsMapper.updateByPrimaryKeyWithBLOBs(model);
}

View File

@ -253,6 +253,13 @@ public class ApiScenarioReportService {
String status = "Success";
report.setStatus(status);
scenarioReportMapper.updateByPrimaryKeySelective(report);
// 把上一条调试的数据内容清空
ApiScenarioReport prevResult = extApiScenarioReportMapper.selectPreviousReportByScenarioId(report.getScenarioId(), reportId);
if (prevResult != null) {
ApiScenarioReportDetailExample example = new ApiScenarioReportDetailExample();
example.createCriteria().andReportIdEqualTo(prevResult.getId());
apiScenarioReportDetailMapper.deleteByExample(example);
}
});
sqlSession.flushStatements();
}

View File

@ -3,11 +3,13 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.automation.EsbDataStruct;
import io.metersphere.api.dto.automation.SaveApiScenarioRequest;
import io.metersphere.api.dto.automation.parse.EsbDataParser;
import io.metersphere.api.dto.definition.ApiDefinitionResult;
import io.metersphere.api.dto.definition.ApiTestCaseResult;
import io.metersphere.api.dto.definition.SaveApiDefinitionRequest;
import io.metersphere.api.dto.definition.SaveApiTestCaseRequest;
import io.metersphere.api.dto.definition.request.MsTestElement;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
@ -313,6 +315,35 @@ public class EsbApiParamService {
return keyValueList;
}
private List<KeyValue> genKeyValueListByDataStruct(MsTCPSampler tcpSampler, List<EsbDataStruct> dataStructRequestList) {
List<KeyValue> keyValueList = new ArrayList<>();
String sendRequest = tcpSampler.getRequest();
String paramRegexStr = "\\$\\{([^}]*)\\}";
try {
if (StringUtils.isNotEmpty(sendRequest)) {
List<String> paramList = new ArrayList<>();
Pattern regex = Pattern.compile(paramRegexStr);
Matcher matcher = regex.matcher(sendRequest);
while (matcher.find()) {
paramList.add(matcher.group(1));
}
for (String param : paramList) {
String value = this.genValueFromEsbDataStructByParam(dataStructRequestList, param);
if (StringUtils.isNotEmpty(value)) {
KeyValue kv = new KeyValue();
kv.setName(param);
kv.setValue(value);
kv.setRequired(true);
keyValueList.add(kv);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return keyValueList;
}
//通过报文模版中的变量参数解析报文数据结构生成对应的xml数据
private String genValueFromEsbDataStructByParam(List<EsbDataStruct> dataStructRequestList, String param) {
String returnValue = "";
@ -341,10 +372,32 @@ public class EsbApiParamService {
return request;
}
public void handleEsbRequest(MsTCPSampler tcpSampler) {
try {
//修改reqeust.parameters, 将树结构类型数据转化为表格类型数据供执行时参数的提取
if (tcpSampler.getEsbDataStruct() != null ) {
List<KeyValue> keyValueList = this.genKeyValueListByDataStruct(tcpSampler, tcpSampler.getEsbDataStruct());
tcpSampler.setParameters(keyValueList);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void deleteByResourceIdIn(List<String> apiIds) {
EsbApiParamsExample example = new EsbApiParamsExample();
example.createCriteria().andResourceIdIn(apiIds);
esbApiParamsMapper.deleteByExample(example);
}
public void checkScenarioRequests(SaveApiScenarioRequest request) {
if(request.getScenarioDefinition() != null ){
List<MsTestElement> hashTreeList = request.getScenarioDefinition().getHashTree();
for (MsTestElement testElement :hashTreeList) {
if(testElement instanceof MsTCPSampler){
this.handleEsbRequest((MsTCPSampler)testElement);
}
}
}
}
}

View File

@ -76,7 +76,7 @@ public class HistoricalDataUpgradeService {
return scenario;
}
private MsScenario createScenario(Scenario oldScenario) {
private MsScenario createScenario(Scenario oldScenario, String projectId) {
MsScenario scenario = new MsScenario();
scenario.setOldVariables(oldScenario.getVariables());
scenario.setName(oldScenario.getName());
@ -397,6 +397,7 @@ public class HistoricalDataUpgradeService {
MsScenario scenarioTest = createScenarioByTest(test);
LinkedList<MsTestElement> listSteps = new LinkedList<>();
List<Scenario> scenarios = JSON.parseArray(test.getScenarioDefinition(), Scenario.class);
String envId = null;
if (CollectionUtils.isNotEmpty(scenarios)) {
// 批量处理
for (Scenario scenario : scenarios) {
@ -405,7 +406,7 @@ public class HistoricalDataUpgradeService {
}
scenario.setId(test.getId() + "=" + scenario.getId());
scenario.setName(test.getName() + "_" + scenario.getName());
MsScenario scenario1 = createScenario(scenario);
MsScenario scenario1 = createScenario(scenario, saveHistoricalDataUpgrade.getProjectId());
String scenarioDefinition = JSON.toJSONString(scenario1);
num++;
createApiScenarioWithBLOBs(saveHistoricalDataUpgrade, scenario.getId(), scenario.getName(), scenario.getRequests().size(), scenarioDefinition, mapper, num);
@ -417,10 +418,17 @@ public class HistoricalDataUpgradeService {
step.setResourceId(UUID.randomUUID().toString());
step.setReferenced("REF");
listSteps.add(step);
if (StringUtils.isNotEmpty(scenario.getEnvironmentId())) {
envId = scenario.getEnvironmentId();
}
}
}
num++;
scenarioTest.setHashTree(listSteps);
if (StringUtils.isNotEmpty(envId)) {
scenarioTest.setEnvironmentId(envId);
}
String scenarioDefinition = JSON.toJSONString(scenarioTest);
createApiScenarioWithBLOBs(saveHistoricalDataUpgrade, scenarioTest.getId(), scenarioTest.getName(), listSteps.size(), scenarioDefinition, mapper, num);
}

View File

@ -3,6 +3,7 @@ package io.metersphere.base.mapper.ext;
import io.metersphere.api.dto.QueryAPIReportRequest;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.base.domain.ApiDefinitionExecResult;
import io.metersphere.base.domain.ApiScenarioReport;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@ -23,4 +24,7 @@ public interface ExtApiScenarioReportMapper {
List<ApiDataCountResult> countByProjectIdGroupByExecuteResult(String projectId);
List<ApiScenarioReport> selectLastReportByIds(@Param("scenarioIdList") List<String> ids);
ApiScenarioReport selectPreviousReportByScenarioId(@Param("scenarioId") String scenarioId, @Param("nowId") String nowId);
}

View File

@ -216,4 +216,9 @@
) orderData ON orderData.id = report.id;
</select>
<select id="selectPreviousReportByScenarioId" resultType="io.metersphere.base.domain.ApiScenarioReport">
select * from api_scenario_report
WHERE execute_type in ("Completed","Debug") and scenario_id=#{scenarioId} and id != #{nowId} ORDER BY create_time desc LIMIT 1
</select>
</mapper>

View File

@ -10,7 +10,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
public class KafkaProperties {
public static final String KAFKA_PREFIX = "kafka";
private String acks = "all";
private String acks = "0"; // 不要设置all
private String topic;
private String fields;
private String timestamp;

View File

@ -127,12 +127,18 @@ public class DockerTestEngine extends AbstractEngine {
Integer port = node.getPort();
String uri = String.format(BASE_URL + "/jmeter/container/stop/" + testId, ip, port);
ResultHolder result = restTemplateWithTimeOut.getForObject(uri, ResultHolder.class);
if (result == null) {
MSException.throwException(Translator.get("container_delete_fail"));
}
if (!result.isSuccess()) {
MSException.throwException(result.getMessage());
try {
ResultHolder result = restTemplateWithTimeOut.getForObject(uri, ResultHolder.class);
if (result == null) {
MSException.throwException(Translator.get("container_delete_fail"));
}
if (!result.isSuccess()) {
MSException.throwException(result.getMessage());
}
} catch (MSException e) {
throw e;
} catch (Exception e) {
MSException.throwException("Please check node-controller status.");
}
});
}

View File

@ -7,13 +7,13 @@ import io.metersphere.base.mapper.TestResourceMapper;
import io.metersphere.commons.constants.ResourceStatusEnum;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.controller.ResultHolder;
import io.metersphere.dto.NodeDTO;
import io.metersphere.dto.TestResourcePoolDTO;
import io.metersphere.i18n.Translator;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@ -71,12 +71,18 @@ public class NodeResourcePoolService {
private boolean validateNode(NodeDTO node) {
try {
ResponseEntity<String> entity = restTemplateWithTimeOut.getForEntity(String.format(nodeControllerUrl, node.getIp(), node.getPort()), String.class);
return HttpStatus.OK.equals(entity.getStatusCode());
ResponseEntity<ResultHolder> entity = restTemplateWithTimeOut.getForEntity(String.format(nodeControllerUrl, node.getIp(), node.getPort()), ResultHolder.class);
ResultHolder body = entity.getBody();
if (body == null) {
return false;
}
if (body.getData() != null && StringUtils.equalsIgnoreCase("OK", body.getData().toString())) {
return true;
}
} catch (Exception e) {
LogUtil.error(e.getMessage(), e);
return false;
}
return false;
}
private void updateTestResource(TestResource testResource) {

View File

@ -409,7 +409,7 @@ public class TestPlanService {
|| StringUtils.equals(res, "success")
|| StringUtils.equals(res, ScenarioStatus.Success.name())) {
passNum++;
} else if (res == null) {
} else if (res == null || StringUtils.equals(TestPlanStatus.Prepare.name(), res)) {
prepareNum++;
} else {
failNum++;

View File

@ -67,7 +67,7 @@
import MsAsideContainer from "@/business/components/common/components/MsAsideContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
import MsApiScenarioList from "@/business/components/api/automation/scenario/ApiScenarioList";
import {getUUID, downloadFile, checkoutTestManagerOrTestUser} from "@/common/js/utils";
import {getUUID, downloadFile, checkoutTestManagerOrTestUser,getCurrentUser} from "@/common/js/utils";
import MsApiScenarioModule from "@/business/components/api/automation/scenario/ApiScenarioModule";
import MsEditApiScenario from "./scenario/EditApiScenario";
@ -127,7 +127,6 @@
'$route'(to, from) { // ctrl s
if (to.path.indexOf('/api/automation') == -1) {
if (this.$refs && this.$refs.autoScenarioConfig) {
// console.log(this.$refs.autoScenarioConfig);
this.$refs.autoScenarioConfig.forEach(item => {
item.removeListener();
});
@ -189,7 +188,16 @@
let label = this.$t('api_test.automation.add_scenario');
let name = getUUID().substring(0, 8);
this.activeName = name;
this.tabs.push({label: label, name: name, currentScenario: {apiScenarioModuleId: "", id: getUUID()}});
let currentScenario = {
status: "Underway", principal: getCurrentUser().id,
apiScenarioModuleId: "root", id: getUUID(),
modulePath: "/" + this.$t("commons.module_title")
};
if (this.nodeTree && this.nodeTree.length > 0) {
currentScenario.apiScenarioModuleId = this.nodeTree[0].id;
currentScenario.modulePath = this.nodeTree[0].path;
}
this.tabs.push({label: label, name: name, currentScenario: currentScenario});
}
if (tab.name === 'edit') {
let label = this.$t('api_test.automation.add_scenario');

View File

@ -29,7 +29,7 @@
@refresh="refresh"
ref="basisScenario"/>
<api-import ref="apiImport" :moduleOptions="moduleOptions" @refreshAll="$emit('refreshAll')"/>
<api-import ref="apiImport" :moduleOptions="extendTreeNodes" @refreshAll="$emit('refreshAll')"/>
</div>
</template>
@ -38,7 +38,7 @@
import SelectMenu from "../../../track/common/SelectMenu";
import MsAddBasisScenario from "@/business/components/api/automation/scenario/AddBasisScenario";
import MsNodeTree from "../../../track/common/NodeTree";
import {buildNodePath} from "../../definition/model/NodeTree";
import {buildNodePath, buildTree} from "../../definition/model/NodeTree";
import ModuleTrashButton from "../../definition/components/module/ModuleTrashButton";
import ApiImport from "./common/ScenarioImport";
import MsSearchBar from "@/business/components/common/components/search/MsSearchBar";
@ -82,9 +82,10 @@
trashEnable: false
},
data: [],
extendTreeNodes: [],
currentModule: undefined,
moduleOptions: [],
operators: [
operators: [
{
label: this.$t('api_test.automation.add_scenario'),
callback: this.addScenario
@ -97,7 +98,7 @@
label: this.$t('report.export'),
children: [
{
label: this.$t('report.export_to_ms_format') ,
label: this.$t('report.export_to_ms_format'),
callback: () => {
this.$emit('exportAPI');
}
@ -187,11 +188,17 @@
this.result = this.$get(url, response => {
if (response.data != undefined && response.data != null) {
this.data = response.data;
let moduleOptions = [];
this.data.forEach(node => {
buildNodePath(node, {path: ''}, moduleOptions);
this.extendTreeNodes = [];
this.extendTreeNodes.unshift({
"id": "root",
"name": this.$t('commons.module_title'),
"level": 0,
"children": this.data,
});
this.$emit('setModuleOptions', moduleOptions);
this.extendTreeNodes.forEach(node => {
buildTree(node, {path: ''});
});
this.$emit('setModuleOptions', this.extendTreeNodes);
this.$emit('setNodeTree', this.data);
if (this.$refs.nodeTree) {
this.$refs.nodeTree.filter(this.condition.filterText);

View File

@ -22,9 +22,7 @@
</el-col>
<el-col :span="7">
<el-form-item :label="$t('test_track.module.module')" prop="apiScenarioModuleId">
<el-select class="ms-scenario-input" size="small" v-model="currentScenario.apiScenarioModuleId">
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
</el-select>
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="currentScenario.apiScenarioModuleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
</el-form-item>
</el-col>
<el-col :span="7">
@ -116,9 +114,7 @@
</el-col>
<el-col :span="6">
<env-popover :env-map="projectEnvMap" :project-ids="projectIds" @setProjectEnvMap="setProjectEnvMap"
:project-list="projectList" ref="envPopover"
:disabled="scenarioDefinition.length < 1"
:is-read-only="scenarioDefinition.length < 1"/>
:project-list="projectList" ref="envPopover"/>
</el-col>
<el-col :span="3">
<el-button :disabled="scenarioDefinition.length < 1" size="mini" type="primary" v-prevent-re-click @click="runDebug">{{$t('api_test.request.debug')}}</el-button>
@ -204,10 +200,7 @@
</template>
<maximize-scenario :scenario-definition="scenarioDefinition" :envMap="projectEnvMap" :moduleOptions="moduleOptions"
:currentScenario="currentScenario" :type="type" ref="maximizeScenario" @openScenario="openScenario"
:isHaveExec.sync="isHaveExec" :isExecWithOutEnv.sync="isExecWithOutEnv" :projectList="projectList"
:projectIds.sync="projectIds"
/>
:currentScenario="currentScenario" :type="type" ref="maximizeScenario" @openScenario="openScenario"/>
</ms-drawer>
</div>
@ -244,6 +237,7 @@
import MaximizeScenario from "./maximize/MaximizeScenario";
import ScenarioHeader from "./maximize/ScenarioHeader";
import MsDrawer from "../../../common/components/MsDrawer";
import MsSelectTree from "../../../common/select-tree/SelectTree";
let jsonPath = require('jsonpath');
export default {
@ -266,7 +260,8 @@
EnvPopover,
MaximizeScenario,
ScenarioHeader,
MsDrawer
MsDrawer,
MsSelectTree
},
data() {
return {
@ -274,6 +269,10 @@
label: "label",
children: "hashTree"
},
moduleObj: {
id: 'id',
label: 'name',
},
rules: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
@ -316,8 +315,6 @@
projectList: [],
debugResult: new Map,
drawer: false,
isHaveExec: false,
isExecWithOutEnv: true
}
},
created() {
@ -450,6 +447,10 @@
},
},
methods: {
setModule(id,data) {
this.currentScenario.apiScenarioModuleId = id;
this.currentScenario.modulePath = data.path;
},
setHideBtn() {
this.isBtnHide = false;
},
@ -588,25 +589,9 @@
if (arr[i].type === ELEMENT_TYPE.LoopController && arr[i].loopType === "LOOP_COUNT" && arr[i].hashTree && arr[i].hashTree.length > 1) {
arr[i].countController.proceed = true;
}
let type = arr[i].type;
const canExec = this.checkCanExec(type);
if (!this.isHaveExec) {
//
this.isHaveExec = canExec;
}
if (canExec) {
const execWithOutEnv = this.canExecWithOutEnv(type, arr[i].url);
if (!execWithOutEnv) {
if (!arr[i].projectId) {
// IDIDIDID
arr[i].projectId = scenarioProjectId ? scenarioProjectId : this.projectId;
}
this.projectIds.add(arr[i].projectId);
}
}
if (this.isExecWithOutEnv) {
this.isExecWithOutEnv = this.canExecWithOutEnv(type, arr[i].url)
if (!arr[i].projectId) {
// IDIDIDID
arr[i].projectId = scenarioProjectId ? scenarioProjectId : this.projectId;
}
if (arr[i].hashTree != undefined && arr[i].hashTree.length > 0) {
@ -618,21 +603,7 @@
}
}
},
canExecWithOutEnv(type, path) {
return type !== ELEMENT_TYPE.HTTPSamplerProxy ? !this.checkCanExec(type) : this.isHTTPFullPath(path);
},
isHTTPFullPath(path) {
return path ? path.startsWith("http://") || path.startsWith("https://") : false;
},
checkCanExec(type) {
const allCanExecType = ELEMENTS.get("AllCanExecType");
const index = allCanExecType.indexOf(type);
return index !== -1;
},
sort() {
this.projectIds.clear();
this.isHaveExec = false;
this.isExecWithOutEnv = true;
for (let i in this.scenarioDefinition) {
//
this.scenarioDefinition[i].index = Number(i) + 1;
@ -646,22 +617,6 @@
this.scenarioDefinition[i].projectId = this.projectId;
}
let type = this.scenarioDefinition[i].type;
const canExec = this.checkCanExec(type);
if (!this.isHaveExec) {
//
this.isHaveExec = canExec;
}
if (canExec) {
const execWithOutEnv = this.canExecWithOutEnv(type, this.scenarioDefinition[i].url);
if (!execWithOutEnv) {
this.projectIds.add(this.scenarioDefinition[i].projectId);
}
}
if (this.isExecWithOutEnv) {
this.isExecWithOutEnv = this.canExecWithOutEnv(type, this.scenarioDefinition[i].url)
}
if (this.scenarioDefinition[i].hashTree != undefined && this.scenarioDefinition[i].hashTree.length > 0) {
this.recursiveSorting(this.scenarioDefinition[i].hashTree, this.scenarioDefinition[i].projectId);
}
@ -682,6 +637,7 @@
this.customizeRequest = {};
this.sort();
this.reload();
this.initProjectIds();
},
addScenario(arr) {
if (arr && arr.length > 0) {
@ -704,6 +660,7 @@
this.isBtnHide = false;
this.sort();
this.reload();
this.initProjectIds();
},
setApiParameter(item, refType, referenced) {
let request = {};
@ -745,6 +702,7 @@
this.isBtnHide = false;
this.sort();
this.reload();
this.initProjectIds();
},
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
@ -771,6 +729,7 @@
hashTree.splice(index, 1);
this.sort();
this.reload();
this.initProjectIds();
}
}
});
@ -801,19 +760,11 @@
},
runDebug() {
/*触发执行操作*/
if (!this.isHaveExec) {
this.$warning("无可执行步骤!");
let sign = this.$refs.envPopover.checkEnv();
if (!sign) {
return;
}
//
if (!this.isExecWithOutEnv) {
let sign = this.$refs.envPopover.checkEnv();
if (!sign) {
return;
}
}
this.$refs['currentScenario'].validate((valid) => {
if (valid) {
Promise.all([
@ -902,15 +853,6 @@
this.expandedNode.splice(this.expandedNode.indexOf(data.resourceId), 1);
}
},
getPath(id) {
if (id === null) {
return null;
}
let path = this.moduleOptions.filter(function (item) {
return item.id === id ? item.path : "";
});
return path[0].path;
},
setFiles(item, bodyUploadFiles, obj) {
if (item.body) {
if (item.body.kvs) {
@ -1061,6 +1003,7 @@
}
}
this.sort();
this.initProjectIds();
// this.getEnvironments();
})
}
@ -1068,7 +1011,6 @@
setParameter() {
this.currentScenario.stepTotal = this.scenarioDefinition.length;
this.currentScenario.projectId = this.projectId;
this.currentScenario.modulePath = this.getPath(this.currentScenario.apiScenarioModuleId);
// 便
let scenario = {
id: this.currentScenario.id,
@ -1131,8 +1073,19 @@
})
},
refReload() {
this.initProjectIds();
this.reload();
},
initProjectIds() {
//
this.$nextTick(() => {
this.projectIds.clear();
this.scenarioDefinition.forEach(data => {
let arr = jsonPath.query(data, "$..projectId");
arr.forEach(a => this.projectIds.add(a));
})
})
},
detailRefresh(result) {
//
this.debugResult = result;

View File

@ -31,7 +31,7 @@
</el-form-item>
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
<ms-select-tree size="small" :data="moduleOptions" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="httpForm.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description" style="margin-bottom: 29px">
@ -64,6 +64,7 @@
import {createComponent, Request} from "../../../definition/components/jmeter/components";
import {getUUID} from "@/common/js/utils";
import MsSelectTree from "@/business/components/common/select-tree/SelectTree";
import {buildTree} from "../../../definition/model/NodeTree";
export default {
@ -83,7 +84,7 @@
callback();
};
return {
httpForm: {environmentId: ""},
httpForm: {environmentId: "", moduleId: "root"},
moduleOptions: [],
httpVisible: false,
currentModule: {},
@ -250,13 +251,23 @@
let url = "/api/module/list/" + getCurrentProjectID() + "/" + data.protocol;
this.result = this.$get(url, response => {
if (response.data != undefined && response.data != null) {
this.moduleOptions = response.data;
let data = response.data;
this.moduleOptions = [];
this.moduleOptions.unshift({
"id": "root",
"name": this.$t('commons.module_title'),
"level": 0,
"children": data,
});
this.moduleOptions.forEach(node => {
buildTree(node, {path: ''});
});
}
});
},
setModule(id) {
setModule(id, data) {
this.httpForm.moduleId = id;
//this.reload();
this.httpForm.modulePath = data.path;
},
reload() {
this.loading = true
@ -271,7 +282,7 @@
data.protocol = "DUBBO";
}
data.id = getUUID();
this.httpForm = {id: data.id, name: data.name, protocol: data.protocol, path: data.path, method: api.method, userId: getCurrentUser().id, request: data};
this.httpForm = {id: data.id, name: data.name, protocol: data.protocol, path: data.path, method: api.method, userId: getCurrentUser().id, request: data, moduleId: "root"};
this.getMaintainerOptions();
this.list(data);
this.httpVisible = true;

View File

@ -101,25 +101,25 @@ export default {
let requestObj = JSON.parse(item.request);
if(requestObj.esbDataStruct != null ){
//ESB
let param = {};
param.request = requestObj;
param.method = "ESB";
param.esbDataStruct = JSON.stringify(requestObj.esbDataStruct);
if(requestObj.backEsbDataStruct != null){
param.backEsbDataStruct = JSON.stringify(requestObj.backEsbDataStruct);
}else{
param.backEsbDataStruct = "";
}
// //ESB
// let param = {};
// param.request = requestObj;
// param.method = "ESB";
// param.esbDataStruct = JSON.stringify(requestObj.esbDataStruct);
// if(requestObj.backEsbDataStruct != null){
// param.backEsbDataStruct = JSON.stringify(requestObj.backEsbDataStruct);
// }else{
// param.backEsbDataStruct = "";
// }
this.$post("/api/definition/updateEsbRequest", param, response => {
if(response.data!=null){
if(response.data.request!=null){
item.request = JSON.stringify(response.data.request);
param.method = "TCP";
}
}
})
// this.$post("/api/definition/updateEsbRequest", param, response => {
// if(response.data!=null){
// if(response.data.request!=null){
// item.request = JSON.stringify(response.data.request);
// param.method = "TCP";
// }
// }
// })
}
});
this.$emit('save', apiCases, 'CASE', reference);

View File

@ -28,9 +28,12 @@
<div class="header-right" @click.stop>
<slot name="message"></slot>
<el-tooltip :content="$t('test_resource_pool.enable_disable')" placement="top" v-if="showBtn">
<el-switch v-model="data.enable" class="enable-switch" size="mini" :disabled="data.disabled && !data.root"/>
<el-switch v-model="data.enable" class="enable-switch" size="mini" :disabled="data.disabled && !data.root" style="width: 30px"/>
</el-tooltip>
<slot name="button"></slot>
<el-tooltip content="Copy" placement="top">
<el-button size="mini" icon="el-icon-copy-document" circle @click="copyRow" style="padding: 5px"/>
</el-tooltip>
<step-extend-btns style="display: contents" :data="data" @copy="copyRow" @remove="remove" @openScenario="openScenario" v-if="showBtn && (!data.disabled || data.root)"/>
</div>

View File

@ -22,11 +22,9 @@
<el-row>
<el-col :span="11">
<el-form-item :label="$t('commons.import_module')">
<el-select size="small" v-model="formData.moduleId" class="project-select" clearable>
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
</el-select>
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="formData.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
</el-form-item>
<el-form-item v-if="!isHar" :label="$t('commons.import_mode')">
<el-form-item v-if="!isHar" :label="$t('commons.import_mode')">
<el-select size="small" v-model="formData.modeId" class="project-select" clearable>
<el-option v-for="item in modeOptions" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
@ -70,16 +68,17 @@
<script>
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
import MsSelectTree from "../../../../common/select-tree/SelectTree";
export default {
name: "ScenarioImport",
components: {MsDialogFooter},
components: {MsDialogFooter, MsSelectTree},
props: {
saved: {
type: Boolean,
default: true,
},
moduleOptions: {}
moduleOptions: Array,
},
data() {
return {
@ -140,7 +139,11 @@
},
rules: {},
currentModule: {},
fileList: []
fileList: [],
moduleObj: {
id: 'id',
label: 'name',
},
}
},
activated() {
@ -257,7 +260,11 @@
this.fileList = [];
removeGoBackListener(this.close);
this.visible = false;
}
},
setModule(id, data) {
this.formData.moduleId = id;
this.formData.modulePath = data.path;
},
}
}
</script>

View File

@ -23,7 +23,7 @@
<template v-slot:button>
<el-tooltip :content="$t('api_test.run')" placement="top">
<el-button @click="run" icon="el-icon-video-play" class="ms-btn" size="mini" circle/>
<el-button @click="run" icon="el-icon-video-play" style="padding: 5px" class="ms-btn" size="mini" circle/>
</el-tooltip>
</template>
@ -289,6 +289,9 @@
},
active(item) {
this.request.active = !this.request.active;
if (this.node) {
this.node.expanded = this.request.active;
}
this.reload();
},
run() {

View File

@ -105,11 +105,11 @@
remove() {
this.$emit('remove', this.scenario, this.node);
},
active(item) {
if (item && item.active) {
item.active = !item.active;
active() {
if (this.node) {
this.node.expanded = !this.node.expanded;
}
this.reload();
}
},
copyRow() {
this.$emit('copyRow', this.scenario, this.node);

View File

@ -61,6 +61,9 @@
},
active() {
this.request.active = !this.request.active;
if (this.node) {
this.node.expanded = this.request.active;
}
},
}
}

View File

@ -27,7 +27,7 @@
</template>
<template v-slot:button>
<el-button @click="runDebug" :tip="$t('api_test.run')" icon="el-icon-video-play" style="background-color: #409EFF;color: white;" size="mini" circle/>
<el-button @click="runDebug" :tip="$t('api_test.run')" icon="el-icon-video-play" style="background-color: #409EFF;color: white;padding: 5px" size="mini" circle/>
</template>
<div v-if="controller.loopType==='LOOP_COUNT'" draggable>
<el-row>
@ -246,6 +246,9 @@
},
active(item) {
item.active = !item.active;
if (this.node) {
this.node.expanded = item.active;
}
this.reload();
},
changeRadio() {

View File

@ -5,7 +5,7 @@
<el-icon class="el-icon-more"></el-icon>
</el-link>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="copy">复制步骤</el-dropdown-item>
<!--<el-dropdown-item command="copy">复制步骤</el-dropdown-item>-->
<el-dropdown-item command="remove" v-tester>删除步骤</el-dropdown-item>
<el-dropdown-item command="scenarioVar" v-tester v-if="data.type==='scenario'">查看场景变量</el-dropdown-item>
<el-dropdown-item command="openScenario" v-tester v-if="data.type==='scenario' && data.referenced==='REF'">打开场景</el-dropdown-item>

View File

@ -50,39 +50,41 @@
</div>
</ms-aside-container>
<ms-main-container v-if="!loading">
<!-- 第一层当前节点内容-->
<ms-component-config
:isMax="false"
:showBtn="false"
:type="selectedTreeNode.type"
:scenario="selectedTreeNode"
:response="response"
:currentScenario="currentScenario"
:currentEnvironmentId="currentEnvironmentId"
:node="selectedNode"
:project-list="projectList"
:env-map="projectEnvMap"
:draggable="false"
@remove="remove" @copyRow="copyRow" @suggestClick="suggestClick" @refReload="refReload" @openScenario="openScenario"
v-if="selectedTreeNode && selectedNode"/>
<!-- 请求下还有的子步骤-->
<div v-if="selectedTreeNode && selectedTreeNode.hashTree && showNode(selectedTreeNode)">
<div v-for="item in selectedTreeNode.hashTree" :key="item.id" class="ms-col-one">
<ms-component-config
:showBtn="false"
:isMax="false"
:type="item.type"
:scenario="item"
:response="response"
:currentScenario="currentScenario"
:currentEnvironmentId="currentEnvironmentId"
:project-list="projectList"
:env-map="projectEnvMap"
:draggable="false"
@remove="remove" @copyRow="copyRow" @suggestClick="suggestClick"
@refReload="refReload" @openScenario="openScenario"
v-if="selectedTreeNode && selectedNode"/>
<ms-main-container v-loading="loading">
<div v-if="!loading">
<!-- 第一层当前节点内容-->
<ms-component-config
:isMax="false"
:showBtn="false"
:type="selectedTreeNode.type"
:scenario="selectedTreeNode"
:response="response"
:currentScenario="currentScenario"
:currentEnvironmentId="currentEnvironmentId"
:node="selectedNode"
:project-list="projectList"
:env-map="projectEnvMap"
:draggable="false"
@remove="remove" @copyRow="copyRow" @suggestClick="suggestClick" @refReload="refReload" @openScenario="openScenario"
v-if="selectedTreeNode && selectedNode"/>
<!-- 请求下还有的子步骤-->
<div v-if="selectedTreeNode && selectedTreeNode.hashTree && showNode(selectedTreeNode)">
<div v-for="item in selectedTreeNode.hashTree" :key="item.id" class="ms-col-one">
<ms-component-config
:showBtn="false"
:isMax="false"
:type="item.type"
:scenario="item"
:response="response"
:currentScenario="currentScenario"
:currentEnvironmentId="currentEnvironmentId"
:project-list="projectList"
:env-map="projectEnvMap"
:draggable="false"
@remove="remove" @copyRow="copyRow" @suggestClick="suggestClick"
@refReload="refReload" @openScenario="openScenario"
v-if="selectedTreeNode && selectedNode"/>
</div>
</div>
</div>
</ms-main-container>
@ -162,7 +164,6 @@
type: String,
scenarioDefinition: Array,
envMap: Map,
projectList: Array
},
components: {
MsVariableList,
@ -223,10 +224,8 @@
response: {},
projectIds: new Set,
projectEnvMap: new Map,
// projectList: [],
projectList: [],
debugResult: new Map,
isHaveExec: false,
isExecWithOutEnv: true
}
},
created() {
@ -477,6 +476,7 @@
}
this.selectedTreeNode = data;
this.selectedNode = node;
this.reload();
},
suggestClick(node) {
this.response = {};
@ -499,27 +499,8 @@
if (arr[i].type === ELEMENT_TYPE.LoopController && arr[i].loopType === "LOOP_COUNT" && arr[i].hashTree && arr[i].hashTree.length > 1) {
arr[i].countController.proceed = true;
}
let type = arr[i].type;
const canExec = this.checkCanExec(type);
if (!this.isHaveExec) {
//
this.isHaveExec = canExec;
this.$emit("update:isHaveExec", canExec);
}
if (canExec) {
const execWithOutEnv = this.canExecWithOutEnv(type, arr[i].url);
if (!execWithOutEnv) {
if (!arr[i].projectId) {
// IDIDIDID
arr[i].projectId = scenarioProjectId ? scenarioProjectId : this.projectId;
}
this.projectIds.add(arr[i].projectId);
this.$emit('update:projectIds', this.projectIds);
}
}
if (this.isExecWithOutEnv) {
this.isExecWithOutEnv = this.canExecWithOutEnv(type, arr[i].url);
this.$emit('update:isExecWithOutEnv', this.canExecWithOutEnv(type, arr[i].url))
if (!arr[i].projectId) {
arr[i].projectId = scenarioProjectId ? scenarioProjectId : this.projectId;
}
if (arr[i].hashTree != undefined && arr[i].hashTree.length > 0) {
this.recursiveSorting(arr[i].hashTree, arr[i].projectId);
@ -530,24 +511,7 @@
}
}
},
canExecWithOutEnv(type, path) {
return type !== ELEMENT_TYPE.HTTPSamplerProxy ? !this.checkCanExec(type) : this.isHTTPFullPath(path);
},
isHTTPFullPath(path) {
return path ? path.startsWith("http://") || path.startsWith("https://") : false;
},
checkCanExec(type) {
const allCanExecType = ELEMENTS.get("AllCanExecType");
const index = allCanExecType.indexOf(type);
return index !== -1;
},
sort() {
this.projectIds.clear();
this.$emit('update:projectIds', this.projectIds);
this.isHaveExec = false;
this.isExecWithOutEnv = true;
this.$emit('update:isHaveExec', false);
this.$emit('update:isExecWithOutEnv', true);
for (let i in this.scenarioDefinition) {
//
this.scenarioDefinition[i].index = Number(i) + 1;
@ -561,25 +525,6 @@
this.scenarioDefinition[i].projectId = this.projectId;
}
let type = this.scenarioDefinition[i].type;
const canExec = this.checkCanExec(type);
if (!this.isHaveExec) {
//
this.isHaveExec = canExec;
this.$emit('update:isHaveExec', canExec);
}
if (canExec) {
const execWithOutEnv = this.canExecWithOutEnv(type, this.scenarioDefinition[i].url);
if (!execWithOutEnv) {
this.projectIds.add(this.scenarioDefinition[i].projectId);
this.$emit('update:projectIds', this.projectIds);
}
}
if (this.isExecWithOutEnv) {
this.isExecWithOutEnv = this.canExecWithOutEnv(type, this.scenarioDefinition[i].url);
this.$emit('update:isExecWithOutEnv', this.canExecWithOutEnv(type, this.scenarioDefinition[i].url));
}
if (this.scenarioDefinition[i].hashTree != undefined && this.scenarioDefinition[i].hashTree.length > 0) {
this.recursiveSorting(this.scenarioDefinition[i].hashTree, this.scenarioDefinition[i].projectId);
}
@ -600,6 +545,7 @@
this.customizeRequest = {};
this.sort();
this.reload();
this.initProjectIds();
},
addScenario(arr) {
if (arr && arr.length > 0) {
@ -617,6 +563,7 @@
}
this.sort();
this.reload();
this.initProjectIds();
this.scenarioVisible = false;
},
setApiParameter(item, refType, referenced) {
@ -658,6 +605,7 @@
});
this.sort();
this.reload();
this.initProjectIds();
},
openTagConfig() {
if (!this.projectId) {
@ -678,6 +626,7 @@
hashTree.splice(index, 1);
this.sort();
this.reload();
this.initProjectIds();
}
}
});
@ -974,8 +923,19 @@
refReload(data, node) {
this.selectedTreeNode = data;
this.selectedNode = node;
this.initProjectIds();
this.reload();
},
initProjectIds() {
//
this.$nextTick(() => {
this.projectIds.clear();
this.scenarioDefinition.forEach(data => {
let arr = jsonPath.query(data, "$..projectId");
arr.forEach(a => this.projectIds.add(a));
})
})
},
detailRefresh(result) {
//
this.debugResult = result;

View File

@ -19,8 +19,6 @@
<el-checkbox v-model="cookieShare" @change="setCookieShare" style="margin-right: 20px">共享cookie</el-checkbox>
<env-popover :env-map="envMap" :project-ids="projectIds" @setProjectEnvMap="setProjectEnvMap"
:disabled="scenarioDefinition.length < 1"
:is-read-only="scenarioDefinition.length < 1"
:project-list="projectList" ref="envPopover" class="ms-right"/>
<el-button :disabled="scenarioDefinition.length < 1" size="mini" type="primary" v-prevent-re-click @click="runDebug">{{$t('api_test.request.debug')}}</el-button>

View File

@ -296,8 +296,12 @@
}
let api = {
status: "Underway", method: "GET", userId: getCurrentUser().id,
url: "", protocol: this.currentProtocol, environmentId: ""
url: "", protocol: this.currentProtocol, environmentId: "", moduleId: 'default-module', modulePath: "/" + this.$t("commons.module_title")
};
if (this.nodeTree && this.nodeTree.length > 0) {
api.moduleId = this.nodeTree[0].id;
api.modulePath = this.nodeTree[0].path;
}
this.handleTabsEdit(this.$t('api_test.definition.request.title'), e, api);
},
handleTabClose() {

View File

@ -185,9 +185,6 @@ export default {
}
this.response.body = body;
}
if (this.currentApi.moduleId && this.currentApi.moduleId === "root") {
this.currentApi.moduleId = "";
}
},
saveApi(data) {
this.setParameters(data);

View File

@ -68,8 +68,8 @@
let projectId = "";
// envMap
if (!this.envMap) {
projectId = getCurrentProjectID();
if (!this.envMap || this.envMap.size === 0) {
projectId = this.$store.state.projectId;
} else {
//
projectId = this.runData.projectId;

View File

@ -275,19 +275,13 @@
}
},
addModule(row) {
let url = '/api/module/getModuleByName/' + getCurrentProjectID() + "/" + this.api.protocol;
this.$get(url, response => {
if (response.data) {
this.$emit('refreshModule');
this.saveApi(row, response.data);
}
});
this.saveApi(row, "default-module");
},
saveApi(row, module) {
let data = this.api;
data.name = this.apiCase.name;
data.moduleId = module.id;
data.modulePath = '/bug';
data.moduleId = module;
data.modulePath ="/"+ this.$t('commons.module_title');
this.setParameters(data);
let bodyFiles = this.getBodyUploadFiles(data);
this.$fileUpload("/api/definition/create", null, bodyFiles, data, () => {

View File

@ -10,20 +10,7 @@
</el-col>
<el-col :span="12">
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
<el-select class="ms-http-input" size="small" v-model="basicForm.moduleId" style="width: 100%" @change="reload">
<div v-if="moduleOptions.length>0">
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
</div>
<div v-else>
<el-option :key="0" :value="''">
<div style="margin-left: 40px">
<span style="font-size: 14px;color: #606266;font-weight: 48.93">{{ $t('api_test.definition.select_comp.no_data') }},
</span>
<el-link type="primary" @click="createModules">{{ $t('api_test.definition.select_comp.add_data') }}</el-link>
</div>
</el-option>
</div>
</el-select>
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="basicForm.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
</el-form-item>
</el-col>
</el-row>
@ -73,70 +60,79 @@
</template>
<script>
import {API_STATUS} from "../../model/JsonData";
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
import {API_STATUS} from "../../model/JsonData";
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
import MsSelectTree from "../../../../common/select-tree/SelectTree";
export default {
name: "MsBasisApi",
components: {MsInputTag},
props: {
currentProtocol: {
type: String,
default: "HTTP"
},
moduleOptions: Array,
basisData: {},
},
created() {
this.getMaintainerOptions();
this.basicForm = this.basisData;
},
data() {
return {
basicForm: {},
httpVisible: false,
currentModule: {},
maintainerOptions: [],
loading: false,
rule: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
],
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
moduleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
export default {
name: "MsBasisApi",
components: {MsInputTag, MsSelectTree},
props: {
currentProtocol: {
type: String,
default: "HTTP"
},
moduleOptions: Array,
basisData: {},
},
created() {
this.getMaintainerOptions();
this.basicForm = this.basisData;
},
data() {
return {
basicForm: {},
httpVisible: false,
currentModule: {},
maintainerOptions: [],
moduleObj: {
id: 'id',
label: 'name',
},
loading: false,
rule: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
],
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
moduleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
},
value: API_STATUS[0].id,
options: API_STATUS,
}
},
methods: {
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
this.maintainerOptions = response.data;
});
},
reload() {
this.loading = true
this.$nextTick(() => {
this.loading = false
})
},
setModule(id,data) {
this.basicForm.moduleId = id;
this.basisData.modulePath = data.path;
},
validate() {
this.$refs['basicForm'].validate((valid) => {
if (valid) {
this.$emit('callback');
}
})
},
createModules() {
this.$emit("createRootModelInTree");
},
value: API_STATUS[0].id,
options: API_STATUS,
}
},
methods: {
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
this.maintainerOptions = response.data;
});
},
reload() {
this.loading = true
this.$nextTick(() => {
this.loading = false
})
},
validate() {
this.$refs['basicForm'].validate((valid) => {
if (valid) {
this.$emit('callback');
}
})
},
createModules() {
this.$emit("createRootModelInTree");
},
}
}
</script>
<style scoped>

View File

@ -49,20 +49,7 @@
</el-col>
<el-col :span="7">
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
<el-select class="ms-http-select" size="small" v-model="httpForm.moduleId">
<div v-if="moduleOptions.length>0">
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
</div>
<div v-else>
<el-option :key="0" :value="''">
<div style="margin-left: 40px">
<span style="font-size: 14px;color: #606266;font-weight: 48.93">{{ $t('api_test.definition.select_comp.no_data') }},
</span>
<el-link type="primary" @click="createModules">{{ $t('api_test.definition.select_comp.add_data') }}</el-link>
</div>
</el-option>
</div>
</el-select>
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="httpForm.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
</el-form-item>
</el-col>
@ -109,25 +96,26 @@
<script>
import MsApiRequestForm from "../request/http/ApiHttpRequestForm";
import MsResponseText from "../response/ResponseText";
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
import {API_STATUS, REQ_METHOD} from "../../model/JsonData";
import {KeyValue} from "../../model/ApiTestModel";
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
import MsJsr233Processor from "../../../automation/scenario/component/Jsr233Processor";
import MsApiRequestForm from "../request/http/ApiHttpRequestForm";
import MsResponseText from "../response/ResponseText";
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
import {API_STATUS, REQ_METHOD} from "../../model/JsonData";
import {KeyValue} from "../../model/ApiTestModel";
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
import MsJsr233Processor from "../../../automation/scenario/component/Jsr233Processor";
import MsSelectTree from "../../../../common/select-tree/SelectTree";
export default {
name: "MsAddCompleteHttpApi",
components: {MsJsr233Processor, MsResponseText, MsApiRequestForm, MsInputTag},
data() {
let validateURL = (rule, value, callback) => {
if (!this.httpForm.path.startsWith("/") || this.httpForm.path.match(/\s/) != null) {
callback(this.$t('api_test.definition.request.path_valid_info'));
}
callback();
};
return {
export default {
name: "MsAddCompleteHttpApi",
components: {MsJsr233Processor, MsResponseText, MsApiRequestForm, MsInputTag, MsSelectTree},
data() {
let validateURL = (rule, value, callback) => {
if (!this.httpForm.path.startsWith("/") || this.httpForm.path.match(/\s/) != null) {
callback(this.$t('api_test.definition.request.path_valid_info'));
}
callback();
};
return {
rule: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
@ -147,6 +135,11 @@ export default {
currentModule: {},
reqOptions: REQ_METHOD,
options: API_STATUS,
moduleObj: {
id: 'id',
label: 'name',
},
}
},
props: {moduleOptions: {}, request: {}, response: {}, basisData: {}, syncTabs: Array},
@ -190,7 +183,6 @@ export default {
});
},
setParameter() {
this.httpForm.modulePath = this.getPath(this.httpForm.moduleId);
this.request.path = this.httpForm.path;
this.request.method = this.httpForm.method;
this.httpForm.request.useEnvironment = undefined;
@ -211,15 +203,6 @@ export default {
createModules() {
this.$emit("createRootModelInTree");
},
getPath(id) {
if (id === null) {
return null;
}
let path = this.moduleOptions.filter(function (item) {
return item.id === id ? item.path : "";
});
return path[0].path;
},
urlChange() {
if (!this.httpForm.path || this.httpForm.path.indexOf('?') === -1) return;
let url = this.getURL(this.addProtocol(this.httpForm.path));
@ -248,6 +231,10 @@ export default {
this.$error(this.$t('api_test.request.url_invalid'), 2000);
}
},
setModule(id,data) {
this.httpForm.moduleId = id;
this.httpForm.modulePath = data.path;
},
},
created() {
@ -255,7 +242,6 @@ export default {
if (!this.basisData.environmentId) {
this.basisData.environmentId = "";
}
this.httpForm = JSON.parse(JSON.stringify(this.basisData));
}
}

View File

@ -5,7 +5,7 @@
<el-row>
<el-col :span="12">
<el-form-item :label="$t('commons.name')" prop="name">
<!-- <el-input class="ms-http-input" size="small" v-model="basicForm.name"/>-->
<!-- <el-input class="ms-http-input" size="small" v-model="basicForm.name"/>-->
<el-input v-model="basicForm.name" class="ms-http-input" size="small">
<el-select v-model="basicForm.method" slot="prepend" style="width: 100px" size="small" @change="methodChange">
<el-option v-for="item in methodTypes" :key="item" :label="item" :value="item"/>
@ -16,20 +16,22 @@
</el-col>
<el-col :span="12">
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
<el-select class="ms-http-input" size="small" v-model="basicForm.moduleId" style="width: 100%" @change="reload">
<div v-if="moduleOptions.length>0">
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
</div>
<div v-else>
<el-option :key="0" :value="''">
<div style="margin-left: 40px">
<span style="font-size: 14px;color: #606266;font-weight: 48.93">{{ $t('api_test.definition.select_comp.no_data') }},
</span>
<el-link type="primary" @click="createModules">{{ $t('api_test.definition.select_comp.add_data') }}</el-link>
</div>
</el-option>
</div>
</el-select>
<!--<el-select class="ms-http-input" size="small" v-model="basicForm.moduleId" style="width: 100%" @change="reload">-->
<!--<div v-if="moduleOptions.length>0">-->
<!--<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>-->
<!--</div>-->
<!--<div v-else>-->
<!--<el-option :key="0" :value="''">-->
<!--<div style="margin-left: 40px">-->
<!--<span style="font-size: 14px;color: #606266;font-weight: 48.93">{{ $t('api_test.definition.select_comp.no_data') }},-->
<!--</span>-->
<!--<el-link type="primary" @click="createModules">{{ $t('api_test.definition.select_comp.add_data') }}</el-link>-->
<!--</div>-->
<!--</el-option>-->
<!--</div>-->
<!--</el-select>-->
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="basicForm.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
</el-form-item>
</el-col>
</el-row>
@ -79,77 +81,87 @@
</template>
<script>
import {API_STATUS} from "../../model/JsonData";
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
import {API_STATUS} from "../../model/JsonData";
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
import MsSelectTree from "../../../../common/select-tree/SelectTree";
export default {
name: "MsTcpBasicApi",
components: {MsInputTag},
props: {
currentProtocol: {
type: String,
default: "HTTP"
},
moduleOptions: Array,
methodTypes: Array,
basisData: {},
},
created() {
this.getMaintainerOptions();
this.basicForm = this.basisData;
if(this.basicForm.protocol == null){
this.basicForm.protocol = "TCP";
}
},
data() {
return {
basicForm: {},
httpVisible: false,
currentModule: {},
maintainerOptions: [],
loading: false,
rule: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
],
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
moduleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
export default {
name: "MsTcpBasicApi",
components: {MsInputTag, MsSelectTree},
props: {
currentProtocol: {
type: String,
default: "HTTP"
},
moduleOptions: Array,
methodTypes: Array,
basisData: {},
},
created() {
this.getMaintainerOptions();
this.basicForm = this.basisData;
if (this.basicForm.protocol == null) {
this.basicForm.protocol = "TCP";
}
},
data() {
return {
basicForm: {},
httpVisible: false,
currentModule: {},
maintainerOptions: [],
loading: false,
rule: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
],
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
moduleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
status: [{required: true, message: this.$t('commons.please_select'), trigger: 'change'}],
},
value: API_STATUS[0].id,
options: API_STATUS,
moduleObj: {
id: 'id',
label: 'name',
},
}
},
methods: {
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
this.maintainerOptions = response.data;
});
},
reload() {
this.loading = true
this.$nextTick(() => {
this.loading = false
})
},
validate() {
this.$refs['basicForm'].validate((valid) => {
if (valid) {
this.$emit('callback');
}
})
},
createModules() {
this.$emit("createRootModelInTree");
},
methodChange() {
this.$emit("changeApiProtocol", this.basicForm.method);
},
setModule(id,data) {
this.basisData.modulePath = data.path;
this.basisData.moduleId = id;
},
value: API_STATUS[0].id,
options: API_STATUS,
}
},
methods: {
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
this.maintainerOptions = response.data;
});
},
reload() {
this.loading = true
this.$nextTick(() => {
this.loading = false
})
},
validate() {
this.$refs['basicForm'].validate((valid) => {
if (valid) {
this.$emit('callback');
}
})
},
createModules() {
this.$emit("createRootModelInTree");
},
methodChange() {
this.$emit("changeApiProtocol",this.basicForm.method);
},
}
}
</script>
<style scoped>

View File

@ -178,6 +178,10 @@
<div v-else-if="apiInfo.requestBodyParamType == 'JSON-SCHEMA'" style="margin-left: 10px">
<ms-json-code-edit :body="apiInfo.jsonSchemaBody" ref="jsonCodeEdit"/>
</div>
<!-- <div v-else-if="apiInfo.requestBodyParamType == 'XML'" style="margin-left: 10px">-->
<!-- <ms-json-code-edit :body="apiInfo.jsonSchemaBody" ref="jsonCodeEdit"/>-->
<!-- <editor v-model="formatData" :lang="mode" @init="editorInit" :theme="theme" :height="height"/>-->
<!-- </div>-->
<div v-else class="showDataDiv">
<br/>
<p style="margin: 0px 20px;"
@ -423,7 +427,12 @@ export default {
formatRowData(dataType, data) {
var returnData = data;
if (data) {
returnData = data.replace(/\n/g, '<br>');
if(dataType === 'XML'){
returnData = "<xmp>"+returnData+"</xmp>";
}else{
returnData = data.replace(/\n/g, '<br>');
}
}
return returnData;
},

View File

@ -25,12 +25,10 @@
<el-row>
<el-col :span="11">
<el-form-item :label="$t('commons.import_module')" prop="moduleId">
<el-select size="small" v-model="formData.moduleId" class="project-select" clearable>
<el-option v-for="item in moduleOptions" :key="item.id" :label="item.path" :value="item.id"/>
</el-select>
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="formData.moduleId" @getValue="setModule" :obj="moduleObj" clearable checkStrictly/>
</el-form-item>
<el-form-item v-if="!isScenarioModel&&showImportModel" :label="$t('commons.import_mode')" prop="modeId">
<el-select size="small" v-model="formData.modeId" class="project-select" clearable>
<el-select size="small" v-model="formData.modeId" clearable style="width: 100%">
<el-option v-for="item in modeOptions" :key="item.id" :label="item.name" :value="item.id"/>
</el-select>
</el-form-item>
@ -59,7 +57,7 @@
<el-switch
v-model="swaggerSynchronization"
@click.native="scheduleEdit"
>
>
</el-switch>
<span style="color: #6C317C;cursor: pointer;font-weight: bold;margin-left: 10px" @click="scheduleEditByText">{{$t('api_test.api_import.timing_synchronization')}}</span>
</el-form-item>
@ -98,337 +96,338 @@
</template>
<script>
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
import ScheduleImport from "@/business/components/api/definition/components/import/ImportScheduleEdit";
import MsDialogFooter from "../../../../common/components/MsDialogFooter";
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
import ScheduleImport from "@/business/components/api/definition/components/import/ImportScheduleEdit";
import MsSelectTree from "../../../../common/select-tree/SelectTree";
export default {
name: "ApiImport",
components: {ScheduleImport, MsDialogFooter},
props: {
saved: {
type: Boolean,
default: true,
},
moduleOptions: {},
propotal:String,
model: {
type: String,
default: 'definition'
}
},
data() {
return {
visible: false,
swaggerUrlEnable: false,
swaggerSynchronization: false,
showEnvironmentSelect: true,
modeOptions: [{
id: 'fullCoverage',
name: this.$t('commons.cover')
export default {
name: "ApiImport",
components: {ScheduleImport, MsDialogFooter, MsSelectTree},
props: {
saved: {
type: Boolean,
default: true,
},
{
id: 'incrementalMerge',
name: this.$t('commons.not_cover')
}],
protocol: "",
platforms: [
{
name: 'MeterSphere',
value: 'Metersphere',
tip: this.$t('api_test.api_import.ms_tip'),
exportTip: this.$t('api_test.api_import.ms_export_tip'),
moduleOptions: Array,
propotal: String,
model: {
type: String,
default: 'definition'
}
},
data() {
return {
visible: false,
swaggerUrlEnable: false,
swaggerSynchronization: false,
showEnvironmentSelect: true,
moduleObj: {
id: 'id',
label: 'name',
},
modeOptions: [{
id: 'fullCoverage',
name: this.$t('commons.cover')
},
{
id: 'incrementalMerge',
name: this.$t('commons.not_cover')
}],
protocol: "",
platforms: [
{
name: 'MeterSphere',
value: 'Metersphere',
tip: this.$t('api_test.api_import.ms_tip'),
exportTip: this.$t('api_test.api_import.ms_export_tip'),
suffixes: new Set(['json'])
},
],
postmanPlanform: {
name: 'Postman',
value: 'Postman',
tip: this.$t('api_test.api_import.postman_tip'),
exportTip: this.$t('api_test.api_import.post_export_tip'),
suffixes: new Set(['json'])
},
],
postmanPlanform:{
name: 'Postman',
value: 'Postman',
tip: this.$t('api_test.api_import.postman_tip'),
exportTip: this.$t('api_test.api_import.post_export_tip'),
suffixes: new Set(['json'])
},
swaggerPlanform:{
name: 'Swagger',
value: 'Swagger2',
tip: this.$t('api_test.api_import.swagger_tip'),
exportTip: this.$t('api_test.api_import.swagger_export_tip'),
suffixes: new Set(['json'])
},
harPlanform:{
name: 'HAR',
value: 'Har',
tip: this.$t('api_test.api_import.har_tip'),
exportTip: this.$t('api_test.api_import.har_export_tip'),
suffixes: new Set(['har'])
},
esbPlanform : {
name: 'ESB',
value: 'ESB',
tip: this.$t('api_test.api_import.esb_tip'),
exportTip: this.$t('api_test.api_import.esb_export_tip'),
suffixes: new Set(['xlsx','xls'])
},
selectedPlatform: {},
selectedPlatformValue: 'Metersphere',
result: {},
projects: [],
environments: [],
useEnvironment: false,
formData: {
file: undefined,
swaggerUrl: '',
modeId: this.$t('commons.not_cover'),
moduleId: '',
},
rules: {
modeId: [
{required: true, message: this.$t('commons.please_select_import_mode'), trigger: 'change'},
],
moduleId: [
{required: true, message: this.$t('commons.please_select_import_module'), trigger: 'change'},
],
},
currentModule: {},
fileList: []
}
},
activated() {
this.selectedPlatform = this.platforms[0];
},
created() {
this.platforms.push(this.postmanPlanform);
this.platforms.push(this.swaggerPlanform);
this.platforms.push(this.harPlanform);
},
watch: {
selectedPlatformValue() {
for (let i in this.platforms) {
if (this.platforms[i].value === this.selectedPlatformValue) {
this.selectedPlatform = this.platforms[i];
break;
}
swaggerPlanform: {
name: 'Swagger',
value: 'Swagger2',
tip: this.$t('api_test.api_import.swagger_tip'),
exportTip: this.$t('api_test.api_import.swagger_export_tip'),
suffixes: new Set(['json'])
},
harPlanform: {
name: 'HAR',
value: 'Har',
tip: this.$t('api_test.api_import.har_tip'),
exportTip: this.$t('api_test.api_import.har_export_tip'),
suffixes: new Set(['har'])
},
esbPlanform: {
name: 'ESB',
value: 'ESB',
tip: this.$t('api_test.api_import.esb_tip'),
exportTip: this.$t('api_test.api_import.esb_export_tip'),
suffixes: new Set(['xlsx', 'xls'])
},
selectedPlatform: {},
selectedPlatformValue: 'Metersphere',
result: {},
projects: [],
environments: [],
useEnvironment: false,
formData: {
file: undefined,
swaggerUrl: '',
modeId: this.$t('commons.not_cover'),
moduleId: '',
},
rules: {
modeId: [
{required: true, message: this.$t('commons.please_select_import_mode'), trigger: 'change'},
],
},
currentModule: {},
fileList: []
}
},
propotal(){
let postmanIndex = this.platforms.indexOf(this.postmanPlanform);
let swaggerPlanformIndex = this.platforms.indexOf(this.swaggerPlanform);
let harPlanformIndex = this.platforms.indexOf(this.harPlanform);
let esbPlanformIndex = this.platforms.indexOf(this.esbPlanform);
if(postmanIndex>=0){
this.platforms.splice(this.platforms.indexOf(this.postmanPlanform),1);
}
if(swaggerPlanformIndex>=0){
this.platforms.splice(this.platforms.indexOf(this.swaggerPlanform),1);
}
if(harPlanformIndex>=0){
this.platforms.splice(this.platforms.indexOf(this.harPlanform),1);
}
if(esbPlanformIndex>=0){
this.platforms.splice(this.platforms.indexOf(this.esbPlanform),1);
}
if(this.propotal === 'TCP'){
this.platforms.push(this.esbPlanform);
return true;
}else if(this.propotal === 'HTTP'){
this.platforms.push(this.postmanPlanform);
this.platforms.push(this.swaggerPlanform);
this.platforms.push(this.harPlanform);
return false;
}
}
},
computed: {
isSwagger2() {
return this.selectedPlatformValue === 'Swagger2';
activated() {
this.selectedPlatform = this.platforms[0];
},
showImportModel() {
return this.selectedPlatformValue != 'Har' && this.selectedPlatformValue != 'ESB';
created() {
this.platforms.push(this.postmanPlanform);
this.platforms.push(this.swaggerPlanform);
this.platforms.push(this.harPlanform);
},
showTemplate() {
return this.selectedPlatformValue === 'ESB';
},
isScenarioModel() {
return this.model === 'scenario';
},
projectId() {
return this.$store.state.projectId
},
},
methods: {
scheduleEdit() {
if (!this.formData.swaggerUrl) {
this.$warning(this.$t('commons.please_fill_path'));
this.swaggerSynchronization = !this.swaggerSynchronization
} else {
if (this.swaggerSynchronization) {
this.$refs.scheduleEdit.open(this.buildParam());
}
}
},
scheduleEditByText(){
this.$refs.scheduleEdit.open(this.buildParam());
},
open(module) {
this.currentModule = module;
this.visible = true;
listenGoBack(this.close);
},
upload(file) {
this.formData.file = file.file;
},
handleExceed(files, fileList) {
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
},
handleRemove(file, fileList) {
this.formData.file = undefined;
},
downloadTemplate(){
if(this.selectedPlatformValue == "ESB"){
this.$fileDownload('/api/definition/export/esbExcelTemplate');
}
},
uploadValidate(file, fileList) {
let suffix = file.name.substring(file.name.lastIndexOf('.') + 1);
if (this.selectedPlatform.suffixes && !this.selectedPlatform.suffixes.has(suffix)) {
this.$warning(this.$t('api_test.api_import.suffixFormatErr'));
return false;
}
if (file.size / 1024 / 1024 > 20) {
this.$warning(this.$t('test_track.case.import.upload_limit_size'));
return false;
}
return true;
},
save() {
this.$refs.form.validate(valid => {
if (valid) {
if ((this.selectedPlatformValue != 'Swagger2' || (this.selectedPlatformValue == 'Swagger2' && !this.swaggerUrlEnable)) && !this.formData.file) {
this.$warning(this.$t('commons.please_upload'));
return;
watch: {
selectedPlatformValue() {
for (let i in this.platforms) {
if (this.platforms[i].value === this.selectedPlatformValue) {
this.selectedPlatform = this.platforms[i];
break;
}
let url = '/api/definition/import';
if (this.isScenarioModel) {
url = '/api/automation/import';
}
let param = this.buildParam();
this.result = this.$fileUpload(url, param.file, null, this.buildParam(), response => {
let res = response.data;
this.$success(this.$t('test_track.case.import.success'));
this.visible = false;
this.$emit('refresh', res);
});
} else {
}
},
propotal() {
let postmanIndex = this.platforms.indexOf(this.postmanPlanform);
let swaggerPlanformIndex = this.platforms.indexOf(this.swaggerPlanform);
let harPlanformIndex = this.platforms.indexOf(this.harPlanform);
let esbPlanformIndex = this.platforms.indexOf(this.esbPlanform);
if (postmanIndex >= 0) {
this.platforms.splice(this.platforms.indexOf(this.postmanPlanform), 1);
}
if (swaggerPlanformIndex >= 0) {
this.platforms.splice(this.platforms.indexOf(this.swaggerPlanform), 1);
}
if (harPlanformIndex >= 0) {
this.platforms.splice(this.platforms.indexOf(this.harPlanform), 1);
}
if (esbPlanformIndex >= 0) {
this.platforms.splice(this.platforms.indexOf(this.esbPlanform), 1);
}
if (this.propotal === 'TCP') {
this.platforms.push(this.esbPlanform);
return true;
} else if (this.propotal === 'HTTP') {
this.platforms.push(this.postmanPlanform);
this.platforms.push(this.swaggerPlanform);
this.platforms.push(this.harPlanform);
return false;
}
});
}
},
buildParam() {
let param = {};
Object.assign(param, this.formData);
param.platform = this.selectedPlatformValue;
param.saved = this.saved;
param.model = this.model;
if (this.currentModule) {
param.moduleId = this.formData.moduleId
this.moduleOptions.filter(item => {
if (item.id === this.formData.moduleId) {
param.modulePath = item.path
computed: {
isSwagger2() {
return this.selectedPlatformValue === 'Swagger2';
},
showImportModel() {
return this.selectedPlatformValue != 'Har' && this.selectedPlatformValue != 'ESB';
},
showTemplate() {
return this.selectedPlatformValue === 'ESB';
},
isScenarioModel() {
return this.model === 'scenario';
},
projectId() {
return this.$store.state.projectId
},
},
methods: {
scheduleEdit() {
if (!this.formData.swaggerUrl) {
this.$warning(this.$t('commons.please_fill_path'));
this.swaggerSynchronization = !this.swaggerSynchronization
} else {
if (this.swaggerSynchronization) {
this.$refs.scheduleEdit.open(this.buildParam());
}
})
param.modeId = this.formData.modeId
}
},
scheduleEditByText() {
this.$refs.scheduleEdit.open(this.buildParam());
},
open(module) {
this.currentModule = module;
this.visible = true;
listenGoBack(this.close);
},
upload(file) {
this.formData.file = file.file;
},
handleExceed(files, fileList) {
this.$warning(this.$t('test_track.case.import.upload_limit_count'));
},
handleRemove(file, fileList) {
this.formData.file = undefined;
},
downloadTemplate() {
if (this.selectedPlatformValue == "ESB") {
this.$fileDownload('/api/definition/export/esbExcelTemplate');
}
},
uploadValidate(file, fileList) {
let suffix = file.name.substring(file.name.lastIndexOf('.') + 1);
if (this.selectedPlatform.suffixes && !this.selectedPlatform.suffixes.has(suffix)) {
this.$warning(this.$t('api_test.api_import.suffixFormatErr'));
return false;
}
if (file.size / 1024 / 1024 > 20) {
this.$warning(this.$t('test_track.case.import.upload_limit_size'));
return false;
}
return true;
},
save() {
this.$refs.form.validate(valid => {
if (valid) {
if ((this.selectedPlatformValue != 'Swagger2' || (this.selectedPlatformValue == 'Swagger2' && !this.swaggerUrlEnable)) && !this.formData.file) {
this.$warning(this.$t('commons.please_upload'));
return;
}
let url = '/api/definition/import';
if (this.isScenarioModel) {
url = '/api/automation/import';
}
let param = this.buildParam();
this.result = this.$fileUpload(url, param.file, null, this.buildParam(), response => {
let res = response.data;
this.$success(this.$t('test_track.case.import.success'));
this.visible = false;
this.$emit('refresh', res);
});
} else {
return false;
}
});
},
setModule(id, data) {
this.formData.moduleId = id;
this.formData.modulePath = data.path;
},
buildParam() {
let param = {};
Object.assign(param, this.formData);
param.platform = this.selectedPlatformValue;
param.saved = this.saved;
param.model = this.model;
if (this.currentModule) {
param.moduleId = this.formData.moduleId
param.modeId = this.formData.modeId
}
param.projectId = this.projectId;
if (!this.swaggerUrlEnable) {
param.swaggerUrl = undefined;
}
return param;
},
close() {
this.formData = {
file: undefined,
swaggerUrl: ''
};
this.fileList = [];
removeGoBackListener(this.close);
this.visible = false;
}
param.projectId = this.projectId;
if (!this.swaggerUrlEnable) {
param.swaggerUrl = undefined;
}
return param;
},
close() {
this.formData = {
file: undefined,
swaggerUrl: ''
};
this.fileList = [];
removeGoBackListener(this.close);
this.visible = false;
}
}
}
</script>
<style scoped>
.api-import >>> .el-dialog {
min-width: 750px;
}
.api-import >>> .el-dialog {
min-width: 750px;
}
.format-tip {
background: #EDEDED;
}
.format-tip {
background: #EDEDED;
}
.api-upload {
text-align: center;
margin: auto 0;
}
.api-upload {
text-align: center;
margin: auto 0;
}
.api-upload >>> .el-upload {
width: 100%;
max-width: 350px;
}
.api-upload >>> .el-upload {
width: 100%;
max-width: 350px;
}
.api-upload >>> .el-upload-dragger {
width: 100%;
}
.api-upload >>> .el-upload-dragger {
width: 100%;
}
.el-radio-group {
margin: 10px 0;
}
.el-radio-group {
margin: 10px 0;
}
.el-radio {
margin-right: 20px;
}
.el-radio {
margin-right: 20px;
}
.header-bar, .format-tip, .el-form {
border: solid #E1E1E1 1px;
margin: 10px 0;
padding: 10px;
border-radius: 3px;
}
.header-bar, .format-tip, .el-form {
border: solid #E1E1E1 1px;
margin: 10px 0;
padding: 10px;
border-radius: 3px;
}
.header-bar {
padding: 10px 30px;
}
.header-bar {
padding: 10px 30px;
}
.api-import >>> .el-dialog__body {
padding: 15px 25px;
}
.api-import >>> .el-dialog__body {
padding: 15px 25px;
}
.operate-button {
float: right;
}
.operate-button {
float: right;
}
.save-button {
margin-left: 10px;
}
.save-button {
margin-left: 10px;
}
.el-form {
padding: 30px 10px;
}
.el-form {
padding: 30px 10px;
}
.dialog-footer {
float: right;
}
.dialog-footer {
float: right;
}
.swagger-url-disable {
margin-top: 10px;
.swagger-url-disable {
margin-top: 10px;
margin-left: 80px;
}
margin-left: 80px;
}
.el-divider {
height: 200px;
}
.el-divider {
height: 200px;
}
</style>

View File

@ -157,7 +157,7 @@ import {parseEnvironment} from "@/business/components/api/test/model/Environment
import MsTableHeaderSelectPopover from "@/business/components/common/components/table/MsTableHeaderSelectPopover";
import MsTableAdvSearchBar from "@/business/components/common/components/search/MsTableAdvSearchBar";
import {API_CASE_CONFIGS} from "@/business/components/common/components/search/search-components";
import {_filter, _handleSelect, _handleSelectAll, _sort, getLabel, getSystemLabel,} from "@/common/js/tableUtils";
import {_filter, _handleSelect, _handleSelectAll, _sort, getLabel} from "@/common/js/tableUtils";
import {API_CASE_LIST} from "@/common/js/constants";
import {Api_Case_List} from "@/business/components/common/model/JsonData";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
@ -263,7 +263,6 @@ export default {
},
created: function () {
this.initTable();
getSystemLabel(this, this.type)
this.$nextTick(() => {
this.$refs.caseTable.bodyWrapper.scrollTop = 5
})

View File

@ -235,7 +235,7 @@
import {
_handleSelect,
_handleSelectAll, buildBatchParam, getLabel,
getSelectDataCounts, getSystemLabel, initCondition,
getSelectDataCounts, initCondition,
setUnSelectIds, toggleAllSelection
} from "@/common/js/tableUtils";
import {_filter, _sort} from "@/common/js/tableUtils";
@ -380,7 +380,6 @@
} else {
this.condition.filters = {status: ["Prepare", "Underway", "Completed"]};
}
this.getSystemLabel(this.type)
this.initTable();
this.getMaintainerOptions();
},
@ -405,15 +404,6 @@
}
},
methods: {
getSystemLabel(type) {
let param = {}
param.type = type
this.$post('/system/system/header', param, response => {
if (response.data != null) {
this.tableLabel = eval(response.data.props);
}
})
},
customHeader() {
this.$refs.headerCustom.open(this.tableLabel)
},

View File

@ -20,6 +20,7 @@
:condition="condition"
:current-module="currentModule"
:is-read-only="isReadOnly"
:moduleOptions="data"
@exportAPI="exportAPI"
@saveAsEdit="saveAsEdit"
@refreshTable="$emit('refreshTable')"
@ -34,25 +35,25 @@
</template>
<script>
import MsAddBasisApi from "../basis/AddBasisApi";
import SelectMenu from "../../../../track/common/SelectMenu";
import {OPTIONS} from "../../model/JsonData";
import ApiImport from "../import/ApiImport";
import MsNodeTree from "../../../../track/common/NodeTree";
import ApiModuleHeader from "./ApiModuleHeader";
import {buildNodePath} from "../../model/NodeTree";
import MsAddBasisApi from "../basis/AddBasisApi";
import SelectMenu from "../../../../track/common/SelectMenu";
import {OPTIONS} from "../../model/JsonData";
import ApiImport from "../import/ApiImport";
import MsNodeTree from "../../../../track/common/NodeTree";
import ApiModuleHeader from "./ApiModuleHeader";
import {buildNodePath, buildTree} from "../../model/NodeTree";
export default {
name: 'MsApiModule',
components: {
ApiModuleHeader,
MsNodeTree,
MsAddBasisApi,
SelectMenu,
ApiImport
},
data() {
return {
export default {
name: 'MsApiModule',
components: {
ApiModuleHeader,
MsNodeTree,
MsAddBasisApi,
SelectMenu,
ApiImport
},
data() {
return {
result: {},
condition: {
protocol: OPTIONS[0].value,
@ -129,11 +130,17 @@ export default {
this.result = this.$get(url, response => {
if (response.data != undefined && response.data != null) {
this.data = response.data;
let moduleOptions = [];
this.data.forEach(node => {
buildNodePath(node, {path: ''}, moduleOptions);
this.data.unshift({
"id": "default-module",
"name": this.$t('commons.module_title'),
"level": 0,
"path": "/" + this.$t('commons.module_title'),
"children": [],
});
this.$emit('setModuleOptions', moduleOptions);
this.data.forEach(node => {
buildTree(node, {path: ''});
});
this.$emit('setModuleOptions', this.data);
this.$emit('setNodeTree', this.data);
if (this.$refs.nodeTree) {
this.$refs.nodeTree.filter(this.condition.filterText);

View File

@ -31,143 +31,128 @@
</template>
<script>
import {OPTIONS} from "../../model/JsonData";
import MsAddBasisApi from "../basis/AddBasisApi";
import ApiImport from "../import/ApiImport";
import ModuleTrashButton from "./ModuleTrashButton";
import {buildNodePath} from "@/business/components/api/definition/model/NodeTree";
import TemplateComponent from "../../../../track/plan/view/comonents/report/TemplateComponent/TemplateComponent";
import MsSearchBar from "@/business/components/common/components/search/MsSearchBar";
export default {
name: "ApiModuleHeader",
components: {MsSearchBar, TemplateComponent, ModuleTrashButton, ApiImport, MsAddBasisApi},
data() {
return {
options: OPTIONS,
moduleOptions: {},
operators: [
{
label: this.$t('api_test.definition.request.title'),
callback: this.addApi
},
{
label: this.$t('api_test.definition.request.fast_debug'),
callback: () => {this.$emit('debug')}
},
{
label: this.$t('api_test.api_import.label'),
callback: this.handleImport
},
{
label: this.$t('report.export'),
children: [
{
label: this.$t('report.export_to_ms_format') ,
callback: () => {
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
import {OPTIONS} from "../../model/JsonData";
import MsAddBasisApi from "../basis/AddBasisApi";
import ApiImport from "../import/ApiImport";
import ModuleTrashButton from "./ModuleTrashButton";
import {buildNodePath} from "@/business/components/api/definition/model/NodeTree";
import TemplateComponent from "../../../../track/plan/view/comonents/report/TemplateComponent/TemplateComponent";
import MsSearchBar from "@/business/components/common/components/search/MsSearchBar";
export default {
name: "ApiModuleHeader",
components: {MsSearchBar, TemplateComponent, ModuleTrashButton, ApiImport, MsAddBasisApi},
data() {
return {
options: OPTIONS,
operators: [
{
label: this.$t('api_test.definition.request.title'),
callback: this.addApi
},
{
label: this.$t('api_test.definition.request.fast_debug'),
callback: () => {this.$emit('debug')}
},
{
label: this.$t('api_test.api_import.label'),
callback: this.handleImport
},
{
label: this.$t('report.export'),
children: [
{
label: this.$t('report.export_to_ms_format') ,
callback: () => {
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
this.$emit('exportAPI', 'MS');
}
this.$emit('exportAPI', 'MS');
}
},
{
label: this.$t('report.export_to_swagger3_format'),
callback: () => {
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
},
{
label: this.$t('report.export_to_swagger3_format'),
callback: () => {
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
this.$emit('exportAPI', 'Swagger');
}
this.$emit('exportAPI', 'Swagger');
}
}
]
]
}
]
}
},
props: {
condition: {
type: Object,
default() {
return {}
}
]
}
},
props: {
condition: {
type: Object,
default() {
return {}
}
},
currentModule: {
type: Object,
default() {
return {}
}
},
isReadOnly: {
type: Boolean,
default() {
return false
}
},
},
computed: {
projectId() {
return this.$store.state.projectId
},
},
methods: {
handleImport() {
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
this.protocol = "HTTP";
this.result = this.$get("/api/module/list/" + this.projectId + "/" + this.condition.protocol, response => {
if (response.data != undefined && response.data != null) {
this.data = response.data;
let moduleOptions = [];
this.data.forEach(node => {
buildNodePath(node, {path: ''}, moduleOptions);
});
this.moduleOptions = moduleOptions
},
moduleOptions: Array,
currentModule: {
type: Object,
default() {
return {}
}
},
isReadOnly: {
type: Boolean,
default() {
return false
}
},
},
computed: {
projectId() {
return this.$store.state.projectId
},
},
methods: {
handleImport() {
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
this.protocol = "HTTP";
this.$refs.apiImport.open(this.moduleOptions);
});
},
addApi() {
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
},
addApi() {
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
this.$refs.basisApi.open(this.currentModule);
},
saveAsEdit(data) {
this.$emit('saveAsEdit', data);
},
refresh() {
this.$emit('refresh');
},
enableTrash() {
this.condition.trashEnable = true;
}
this.$refs.basisApi.open(this.currentModule);
},
saveAsEdit(data) {
this.$emit('saveAsEdit', data);
},
refresh() {
this.$emit('refresh');
},
enableTrash() {
this.condition.trashEnable = true;
}
}
}
</script>
<style scoped>
.protocol-select {
width: 92px;
height: 30px;
}
.protocol-col {
min-width: 93px;
}
.read-only {
width: 150px !important;
}
.filter-input {
width: 174px;
padding-left: 3px;
}
.protocol-select {
width: 92px;
height: 30px;
}
.protocol-col {
min-width: 93px;
}
.read-only {
width: 150px !important;
}
.filter-input {
width: 174px;
padding-left: 3px;
}
</style>

View File

@ -9,4 +9,16 @@ export function buildNodePath(node, option, moduleOptions) {
}
}
}
// 构建树
export function buildTree(node, option) {
option.id = node.id;
option.name = node.name;
option.path = option.path + '/' + node.name;
node.path = option.path;
if (node.children) {
for (let i = 0; i < node.children.length; i++) {
buildTree(node.children[i], {path: option.path});
}
}
}

View File

@ -155,7 +155,7 @@ export default {
width: 100%;
background: white;
height: 100vh;
z-index: 999999;
z-index: 2;
}
.full-screen >>> .minder-container {

View File

@ -52,6 +52,10 @@ export default {
this.defaultCheckedKeys.push(i.id)
}
)
if(this.type==='api_list'||this.type==='api_case_list'||this.type==='api_scenario_list'||this.type==='test_plan_function_test_case'
||this.type==='test_plan_api_case'||this.type==='test_plan_load_case'||this.type==='test_plan_scenario_case'){
this.fieldSelected=items
}
},
saveHeader() {
let param = {

View File

@ -81,7 +81,6 @@ export const Test_Case_Review_Case_List = [
{id: 'name', label: i18n.t('commons.name')},
{id: 'priority', label: i18n.t('test_track.case.priority')},
{id: 'type', label: i18n.t('test_track.case.type')},
{id: 'method', label: i18n.t('test_track.case.method')},
{id: 'nodePath', label: i18n.t('test_track.case.module')},
{id: 'projectName', label: i18n.t('test_track.review.review_project')},
{id: 'reviewerName', label: i18n.t('test_track.review.reviewer')},
@ -107,7 +106,7 @@ export const Test_Plan_Function_Test_Case = [
//测试计划-api用例
export const Test_Plan_Api_Case = [
{id: 'num', label: i18n.t('commons.id')},
{id: 'name', label: i18n.t('commons.name')},
{id: 'name', label: i18n.t('api_test.definition.api_name')},
{id: 'priority', label: i18n.t('test_track.case.priority')},
{id: 'path', label: i18n.t('api_test.definition.api_path')},
{id: 'createUser', label: '创建人'},
@ -124,12 +123,12 @@ export const Test_Plan_Load_Case = [
{id: 'createTime', label: i18n.t('commons.create_time')},
{id: 'status', label: i18n.t('commons.status')},
{id: 'caseStatus', label: i18n.t('test_track.plan.load_case.execution_status')},
{id: 'loadReportId', label: i18n.t('test_track.plan.load_case.view_report')},
{id: 'loadReportId', label: i18n.t('test_track.plan.load_case.report')},
]
//测试计划-场景用例
export const Test_Plan_Scenario_Case = [
{id: 'num', label: i18n.t('commons.id')},
{id: 'name', label: i18n.t('commons.name')},
{id: 'name', label: i18n.t('api_test.automation.scenario_name')},
{id: 'level', label: i18n.t('api_test.automation.case_level')},
{id: 'tagNames', label: i18n.t('api_test.automation.tag')},
{id: 'userId', label: i18n.t('api_test.automation.creator')},

View File

@ -152,10 +152,13 @@
return JSON.stringify(this.data).indexOf(this.obj.children) !== -1 ? this.data : this.switchTree();
},
},
mounted() {
this.init();
},
methods: {
outsideClick(e) {
e.stopPropagation();
this.isShowSelect=false;
this.isShowSelect = false;
},
init() {
if (this.defaultKey != undefined && this.defaultKey.length > 0) {
@ -233,7 +236,9 @@
setKey(thisKey) {
this.$refs.tree.setCurrentKey(thisKey);
let node = this.$refs.tree.getNode(thisKey);
this.setData(node.data);
if (node && node.data) {
this.setData(node.data);
}
},
//
setData(data) {
@ -284,7 +289,7 @@
},
//
popoverHide() {
this.$emit('getValue', this.returnDataKeys, this.returnDatas);
this.$emit('getValue', this.returnDataKeys, this.returnDatas ? this.returnDatas : {});
},
//
clearSelectedNodes() {
@ -340,10 +345,13 @@
// select
this.$refs.select.blur();
},
treeData() {//tree
this.$nextTick(() => {
this.init();
})
treeData: {//tree
handler: function () {
this.$nextTick(() => {
this.init();
})
},
deep: true
},
filterText(val) {
this.$nextTick(() => {

View File

@ -1,24 +1,32 @@
<template>
<div v-loading="result.loading" class="pressure-config-container">
<el-row>
<el-col :span="10">
<el-col :span="12">
<el-collapse v-model="activeNames" accordion>
<el-collapse-item :name="index"
v-for="(threadGroup, index) in threadGroups.filter(th=>th.enabled === 'true' && th.deleted=='false')"
:key="index">
<template slot="title">
<div style="padding-right: 10px">
{{ threadGroup.attributes.testname }}
</div>
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'DURATION'">
{{ $t('load_test.thread_num') }}{{ threadGroup.threadNumber }},
{{ $t('load_test.duration') }}: {{ threadGroup.duration }} {{ getUnitLabel(threadGroup) }}
</el-tag>
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'ITERATION'">
{{ $t('load_test.thread_num') }} {{ threadGroup.threadNumber }},
{{ $t('load_test.iterate_num') }} {{ threadGroup.iterateNum }}
</el-tag>
<el-row>
<el-col :span="14">
<el-tooltip :content="threadGroup.attributes.testname" placement="top">
<div style="padding-right:20px; font-size: 16px;" class="wordwrap">
{{ threadGroup.attributes.testname }}
</div>
</el-tooltip>
</el-col>
<el-col :span="10">
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'DURATION'">
{{ $t('load_test.thread_num') }}{{ threadGroup.threadNumber }},
{{ $t('load_test.duration') }}: {{ threadGroup.duration }} {{ getUnitLabel(threadGroup) }}
</el-tag>
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'ITERATION'">
{{ $t('load_test.thread_num') }} {{ threadGroup.threadNumber }},
{{ $t('load_test.iterate_num') }} {{ threadGroup.iterateNum }}
</el-tag>
</el-col>
</el-row>
</template>
<el-form :inline="true">
<el-form-item :label="$t('load_test.thread_num')">
@ -134,7 +142,7 @@
</el-collapse-item>
</el-collapse>
</el-col>
<el-col :span="14">
<el-col :span="12">
<ms-chart class="chart-container" ref="chart1" :options="options" :autoresize="true"></ms-chart>
</el-col>
</el-row>
@ -578,4 +586,9 @@ export default {
.title {
margin-left: 60px;
}
.wordwrap {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@ -157,7 +157,7 @@ export default {
for (let i = 0; i < rows.length; i++) {
let row = rows[i];
if (this.tableData.filter(f => f.name === row.name).length > 0) {
this.$error(this.$t('load_test.delete_file'));
this.$error(this.$t('load_test.delete_file') + ', name: ' + row.name);
this.selectIds.clear();
return;
}
@ -216,7 +216,7 @@ export default {
}
if (this.tableData.filter(f => f.name === file.name).length > 0) {
this.$error(this.$t('load_test.delete_file'));
this.$error(this.$t('load_test.delete_file') + ', name: ' + file.name);
return false;
}
},

View File

@ -121,7 +121,7 @@ export default {
for (let i = 0; i < rows.length; i++) {
let row = rows[i];
if (this.tableData.filter(f => f.name === row.name + ".jmx").length > 0) {
this.$error(this.$t('load_test.delete_file'));
this.$error(this.$t('load_test.delete_file') + ', name: ' + row.name);
return;
}
}

View File

@ -23,17 +23,25 @@
v-for="(threadGroup, index) in threadGroups.filter(th=>th.enabled === 'true' && th.deleted=='false')"
:key="index">
<template slot="title">
<div style="padding-right: 20px; font-size: 16px;">
{{ threadGroup.attributes.testname }}
</div>
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'DURATION'">
{{ $t('load_test.thread_num') }}{{ threadGroup.threadNumber }},
{{ $t('load_test.duration') }}: {{ threadGroup.duration }} {{ getUnitLabel(threadGroup) }}
</el-tag>
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'ITERATION'">
{{ $t('load_test.thread_num') }} {{ threadGroup.threadNumber }},
{{ $t('load_test.iterate_num') }} {{ threadGroup.iterateNum }}
</el-tag>
<el-row>
<el-col :span="14">
<el-tooltip :content="threadGroup.attributes.testname" placement="top">
<div style="padding-right:20px; font-size: 16px;" class="wordwrap">
{{ threadGroup.attributes.testname }}
</div>
</el-tooltip>
</el-col>
<el-col :span="10">
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'DURATION'">
{{ $t('load_test.thread_num') }}{{ threadGroup.threadNumber }},
{{ $t('load_test.duration') }}: {{ threadGroup.duration }} {{ getUnitLabel(threadGroup) }}
</el-tag>
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'ITERATION'">
{{ $t('load_test.thread_num') }} {{ threadGroup.threadNumber }},
{{ $t('load_test.iterate_num') }} {{ threadGroup.iterateNum }}
</el-tag>
</el-col>
</el-row>
</template>
<el-form :inline="true">
<el-form-item :label="$t('load_test.thread_num')">
@ -110,6 +118,7 @@
<el-input-number
:disabled="isReadOnly"
:min="1"
:max="threadGroup.duration"
v-model="threadGroup.rampUpTime"
@change="calculateTotalChart(threadGroup)"
size="mini"/>
@ -705,4 +714,10 @@ export default {
.title {
margin-left: 60px;
}
.wordwrap {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@ -35,20 +35,8 @@
<el-col :span="7">
<el-form-item :label="$t('test_track.case.module')" :label-width="formLabelWidth" prop="module">
<el-select
v-model="form.module"
:disabled="readOnly"
:placeholder="$t('test_track.case.input_module')"
filterable
class="ms-case-input">
<el-option
v-for="item in moduleOptions"
:key="item.id"
:label="item.path"
:value="item.id"
>
</el-option>
</el-select>
<ms-select-tree :disabled="readOnly" :data="moduleOptions" :defaultKey="form.module" :obj="moduleObj"
@getValue="setModule" clearable checkStrictly size="small" />
</el-form-item>
</el-col>
<el-col :span="7">
@ -292,7 +280,7 @@ import MsDialogFooter from '../../../common/components/MsDialogFooter'
import {getCurrentUser, handleCtrlSEvent, listenGoBack, removeGoBackListener} from "@/common/js/utils";
import {Message} from "element-ui";
import TestCaseAttachment from "@/business/components/track/case/components/TestCaseAttachment";
import {buildNodePath} from "../../../api/definition/model/NodeTree";
import {buildNodePath,buildTree} from "../../../api/definition/model/NodeTree";
import CaseComment from "@/business/components/track/case/components/CaseComment";
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
import MsPreviousNextButton from "../../../common/components/MsPreviousNextButton";
@ -301,12 +289,13 @@ import TestCaseComment from "@/business/components/track/case/components/TestCas
import ReviewCommentItem from "@/business/components/track/review/commom/ReviewCommentItem";
import {API_STATUS, REVIEW_STATUS, TEST} from "@/business/components/api/definition/model/JsonData";
import MsTableButton from "@/business/components/common/components/MsTableButton";
import MsSelectTree from "../../../common/select-tree/SelectTree";
export default {
name: "TestCaseEdit",
components: {
MsTableButton,
MsSelectTree,
ReviewCommentItem,
TestCaseComment, MsPreviousNextButton, MsInputTag, CaseComment, MsDialogFooter, TestCaseAttachment
},
@ -320,12 +309,13 @@ export default {
sysList: [],//
options: REVIEW_STATUS,
statuOptions: API_STATUS,
comments: [],
comments: [],
result: {},
dialogFormVisible: false,
form: {
name: '',
module: '',
module: 'root',
nodePath:'',
maintainer: getCurrentUser().id,
priority: 'P0',
type: '',
@ -381,6 +371,10 @@ export default {
index: 0,
showInputTag: true,
tableType:"",
moduleObj: {
id: 'id',
label: 'name',
},
};
},
props: {
@ -412,6 +406,7 @@ export default {
this.getSelectOptions();
if (this.type === 'edit' || this.type === 'copy') {
this.open(this.currentTestCaseInfo)
this.getComments(this.currentTestCaseInfo)
}
// Cascader : input
setInterval(function () {
@ -421,6 +416,10 @@ export default {
};
});
}, 1000);
if(this.selectNode && this.selectNode.data){
this.form.module = this.selectNode.data.id;
this.form.nodePath = this.selectNode.data.path;
}
},
watch: {
treeNodes() {
@ -433,8 +432,13 @@ export default {
created() {
this.loadOptions();
this.addListener(); // ctrl s
},
methods: {
setModule(id,data) {
this.form.module = id;
this.form.nodePath = data.path;
},
clearInput() {
//this.$refs['cascade'].panel.clearCheckedNodes()
},
@ -740,7 +744,6 @@ export default {
}*/
this.tableType='edit';
this.$emit("refresh",this.form);
console.log(response.data)
this.form.id=response.data
if (this.type === 'add' || this.type === 'copy') {
param.id = response.data;
@ -761,11 +764,6 @@ export default {
Object.assign(param, this.form);
param.steps = JSON.stringify(this.form.steps);
param.nodeId = this.form.module;
this.moduleOptions.forEach(item => {
if (this.form.module === item.id) {
param.nodePath = item.path;
}
});
if (this.projectId) {
param.projectId = this.projectId;
}
@ -838,11 +836,16 @@ export default {
this.getTestOptions()
},
getModuleOptions() {
let moduleOptions = [];
this.treeNodes.forEach(node => {
buildNodePath(node, {path: ''}, moduleOptions);
this.moduleOptions = [];
this.moduleOptions.unshift({
"id": "root",
"name": this.$t('commons.module_title'),
"level": 0,
"children": this.treeNodes,
});
this.moduleOptions.forEach(node => {
buildTree(node, {path: ''});
});
this.moduleOptions = moduleOptions;
},
getMaintainerOptions() {
let workspaceId = localStorage.getItem(WORKSPACE_ID);
@ -920,7 +923,7 @@ export default {
}
if (this.tableData.filter(f => f.name === file.name).length > 0) {
this.$error(this.$t('load_test.delete_file'));
this.$error(this.$t('load_test.delete_file') + ', name: ' + file.name);
return false;
}

View File

@ -161,7 +161,7 @@ import {
_handleSelect,
_handleSelectAll,
_sort, buildBatchParam, getLabel,
getSelectDataCounts, getSystemLabel, initCondition,
getSelectDataCounts, initCondition,
setUnSelectIds,
toggleAllSelection
} from "@/common/js/tableUtils";

View File

@ -225,7 +225,7 @@ import MsDeleteConfirm from "../../../common/components/MsDeleteConfirm";
import {TEST_PLAN_CONFIGS} from "../../../common/components/search/search-components";
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
import MsScheduleMaintain from "@/business/components/api/automation/schedule/ScheduleMaintain"
import {_filter, _sort, getLabel, getSystemLabel} from "@/common/js/tableUtils";
import {_filter, _sort, getLabel} from "@/common/js/tableUtils";
import {TEST_PLAN_LIST} from "@/common/js/constants";
import {Test_Plan_List} from "@/business/components/common/model/JsonData";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
@ -291,7 +291,6 @@ export default {
}
this.isTestManagerOrTestUser = checkoutTestManagerOrTestUser();
this.initTableData();
getSystemLabel(this, this.type)
},
methods: {
inite() {

View File

@ -104,7 +104,7 @@
</template>
</el-table-column>
</template>
<el-table-column v-if="!isReadOnly" :label="$t('commons.operating')" align="center">
<el-table-column v-if="!isReadOnly" :label="$t('commons.operating')" >
<template slot="header">
<header-label-operate @exec="customHeader"/>
</template>
@ -161,7 +161,7 @@ import TestPlanApiCaseResult from "./TestPlanApiCaseResult";
import TestPlan from "../../../../../api/definition/components/jmeter/components/test-plan";
import ThreadGroup from "../../../../../api/definition/components/jmeter/components/thread-group";
import {TEST_PLAN_API_CASE, WORKSPACE_ID} from "@/common/js/constants";
import {_filter, _sort, getLabel, getSystemLabel} from "@/common/js/tableUtils";
import {_filter, _sort, getLabel} from "@/common/js/tableUtils";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import {Test_Plan_Api_Case} from "@/business/components/common/model/JsonData";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
@ -268,7 +268,6 @@ export default {
created: function () {
this.getMaintainerOptions();
this.initTable();
getSystemLabel(this, this.type)
},
activated() {

View File

@ -109,7 +109,7 @@ import MsTableMoreBtn from "../../../../../api/automation/scenario/TableMoreBtn"
import MsScenarioExtendButtons from "@/business/components/api/automation/scenario/ScenarioExtendBtns";
import MsTestPlanList from "../../../../../api/automation/scenario/testplan/TestPlanList";
import TestPlanScenarioListHeader from "./TestPlanScenarioListHeader";
import {_handleSelect, _handleSelectAll, getLabel, getSystemLabel} from "../../../../../../../common/js/tableUtils";
import {_handleSelect, _handleSelectAll, getLabel} from "../../../../../../../common/js/tableUtils";
import MsTableOperatorButton from "../../../../../common/components/MsTableOperatorButton";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import {TEST_CASE_LIST, TEST_PLAN_SCENARIO_CASE} from "@/common/js/constants";
@ -188,7 +188,6 @@ export default {
},
created() {
this.search();
getSystemLabel(this, this.type)
},
watch: {

View File

@ -296,7 +296,7 @@ import BatchEdit from "../../../../case/components/BatchEdit";
import ClassicEditor from "@ckeditor/ckeditor5-build-classic";
import {hub} from "@/business/components/track/plan/event-bus";
import MsTag from "@/business/components/common/components/MsTag";
import {_filter, _sort, getLabel, getSystemLabel} from "@/common/js/tableUtils";
import {_filter, _sort, getLabel} from "@/common/js/tableUtils";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import {Test_Plan_Function_Test_Case} from "@/business/components/common/model/JsonData";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
@ -424,9 +424,6 @@ export default {
beforeDestroy() {
hub.$off("openFailureTestCase");
},
created() {
getSystemLabel(this, this.type)
},
methods: {
customHeader() {
this.$refs.headerCustom.open(this.tableLabel)

View File

@ -100,7 +100,7 @@
</template>
</el-table-column>
</template>
<el-table-column v-if="!isReadOnly" :label="$t('commons.operating')" align="center">
<el-table-column v-if="!isReadOnly" :label="$t('commons.operating')" >
<template slot="header">
<header-label-operate @exec="customHeader"/>
</template>
@ -131,7 +131,7 @@ import MsTablePagination from "@/business/components/common/pagination/TablePagi
import MsPerformanceTestStatus from "@/business/components/performance/test/PerformanceTestStatus";
import MsTableOperatorButton from "@/business/components/common/components/MsTableOperatorButton";
import LoadCaseReport from "@/business/components/track/plan/view/comonents/load/LoadCaseReport";
import {_filter, _sort, getLabel, getSystemLabel} from "@/common/js/tableUtils";
import {_filter, _sort, getLabel} from "@/common/js/tableUtils";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import {TEST_CASE_LIST, TEST_PLAN_LOAD_CASE} from "@/common/js/constants";
import {Test_Plan_Load_Case, Track_Test_Case} from "@/business/components/common/model/JsonData";
@ -198,7 +198,7 @@ export default {
created() {
this.initTable();
this.refreshStatus();
getSystemLabel(this, this.type)
},
watch: {

View File

@ -122,7 +122,7 @@ import {
checkoutTestManagerOrTestUser,
getCurrentWorkspaceId
} from "../../../../../common/js/utils";
import {_filter, _sort, getLabel, getSystemLabel} from "@/common/js/tableUtils";
import {_filter, _sort, getLabel} from "@/common/js/tableUtils";
import PlanStatusTableItem from "../../common/tableItems/plan/PlanStatusTableItem";
import {Test_Case_Review} from "@/business/components/common/model/JsonData";
import {TEST_CASE_LIST, TEST_CASE_REVIEW_LIST} from "@/common/js/constants";
@ -173,7 +173,6 @@ export default {
},
created() {
this.isTestManagerOrTestUser = checkoutTestManagerOrTestUser();
getSystemLabel(this, this.type)
this.initTableData();
},
computed: {

View File

@ -202,7 +202,7 @@ import {
} from "../../../../../../common/js/constants";
import TestReviewTestCaseEdit from "./TestReviewTestCaseEdit";
import ReviewStatus from "@/business/components/track/case/components/ReviewStatus";
import {_filter, _sort, getLabel, getSystemLabel} from "@/common/js/tableUtils";
import {_filter, _sort, getLabel} from "@/common/js/tableUtils";
import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import {Test_Case_Review_Case_List, Track_Test_Case} from "@/business/components/common/model/JsonData";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
@ -296,9 +296,6 @@ export default {
this.refreshTableAndReview();
this.isTestManagerOrTestUser = checkoutTestManagerOrTestUser();
},
created() {
getSystemLabel(this, this.type)
},
methods: {
customHeader() {
this.$refs.headerCustom.open(this.tableLabel)

@ -1 +1 @@
Subproject commit 2115bd28a90854d2b6276a90878934715498c584
Subproject commit 07951ba17aef6f29e50cfd68e40de3266f9a60cd

View File

@ -5,6 +5,7 @@ export default {
pass_rate: 'Pass rate',
execution_times: 'Execution times',
cover: 'Cover',
module_title: 'Default module',
not_cover: 'Not Cover',
import: 'Import',
import_success: 'Import success',

View File

@ -5,6 +5,7 @@ export default {
pass_rate: '通过率',
execution_times: '执行次数',
cover: '覆盖',
module_title: '默认模块',
not_cover: '不覆盖',
import: '导入',
import_success: '导入成功',

View File

@ -5,6 +5,7 @@ export default {
pass_rate: '通過率',
execution_times: '執行次數',
cover: '覆蓋',
module_title: '默認模塊',
not_cover: '不覆蓋',
import: '導入',
import_success: '導入成功',