Merge branch 'master' of https://github.com/metersphere/metersphere
This commit is contained in:
commit
0d8d12b17b
|
@ -1,16 +1,22 @@
|
|||
package io.metersphere.api.controller;
|
||||
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.api.dto.APIReportResult;
|
||||
import io.metersphere.api.dto.DeleteAPIReportRequest;
|
||||
import io.metersphere.api.dto.QueryAPIReportRequest;
|
||||
import io.metersphere.api.dto.automation.APIScenarioReportResult;
|
||||
import io.metersphere.api.service.ApiScenarioReportService;
|
||||
import io.metersphere.commons.constants.RoleConstants;
|
||||
import io.metersphere.commons.utils.PageUtils;
|
||||
import io.metersphere.commons.utils.Pager;
|
||||
import io.metersphere.commons.utils.SessionUtils;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/api/scenario/report")
|
||||
|
@ -20,8 +26,41 @@ public class APIScenarioReportController {
|
|||
@Resource
|
||||
private ApiScenarioReportService apiReportService;
|
||||
|
||||
@GetMapping("/get/{reportId}")
|
||||
public APIReportResult get(@PathVariable String reportId) {
|
||||
@GetMapping("/get/{reportId}/{infoDb}")
|
||||
public APIReportResult get(@PathVariable String reportId,@PathVariable Boolean infoDb) {
|
||||
if(infoDb){
|
||||
return apiReportService.get(reportId);
|
||||
}
|
||||
return apiReportService.getCacheResult(reportId);
|
||||
}
|
||||
|
||||
@PostMapping("/list/{goPage}/{pageSize}")
|
||||
public Pager<List<APIScenarioReportResult>> list(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody QueryAPIReportRequest request) {
|
||||
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
|
||||
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
||||
return PageUtils.setPageInfo(page, apiReportService.list(request));
|
||||
}
|
||||
|
||||
@PostMapping("/add")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||
public String add(@RequestBody APIScenarioReportResult node) {
|
||||
return apiReportService.add(node);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||
public String update(@RequestBody APIScenarioReportResult node) {
|
||||
return apiReportService.update(node);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public void delete(@RequestBody DeleteAPIReportRequest request) {
|
||||
apiReportService.delete(request);
|
||||
}
|
||||
|
||||
@PostMapping("/batch/delete")
|
||||
public void deleteAPIReportBatch(@RequestBody DeleteAPIReportRequest reportRequest) {
|
||||
apiReportService.deleteAPIReportBatch(reportRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.github.pagehelper.Page;
|
|||
import com.github.pagehelper.PageHelper;
|
||||
import io.metersphere.api.dto.automation.ApiScenarioDTO;
|
||||
import io.metersphere.api.dto.automation.ApiScenarioRequest;
|
||||
import io.metersphere.api.dto.automation.RunScenarioRequest;
|
||||
import io.metersphere.api.dto.automation.SaveApiScenarioRequest;
|
||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||
import io.metersphere.api.service.ApiAutomationService;
|
||||
|
@ -36,13 +37,13 @@ public class ApiAutomationController {
|
|||
}
|
||||
|
||||
@PostMapping(value = "/create")
|
||||
public void create(@RequestBody SaveApiScenarioRequest request) {
|
||||
apiAutomationService.create(request);
|
||||
public void create(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
apiAutomationService.create(request, bodyFiles);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/update")
|
||||
public void update(@RequestBody SaveApiScenarioRequest request) {
|
||||
apiAutomationService.update(request);
|
||||
public void update(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
apiAutomationService.update(request, bodyFiles);
|
||||
}
|
||||
|
||||
@GetMapping("/delete/{id}")
|
||||
|
@ -70,9 +71,15 @@ public class ApiAutomationController {
|
|||
return apiAutomationService.getApiScenarios(ids);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/run")
|
||||
@PostMapping(value = "/run/debug")
|
||||
public void runDebug(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
||||
apiAutomationService.run(request, bodyFiles);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/run")
|
||||
public void run(@RequestBody RunScenarioRequest request) {
|
||||
apiAutomationService.run(request);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package io.metersphere.api.dto.automation;
|
||||
|
||||
import io.metersphere.base.domain.ApiScenarioReport;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class APIScenarioReportResult extends ApiScenarioReport {
|
||||
|
||||
private String testName;
|
||||
|
||||
private String projectName;
|
||||
|
||||
private String userName;
|
||||
|
||||
private String content;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package io.metersphere.api.dto.automation;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class RunScenarioRequest {
|
||||
|
||||
private String id;
|
||||
|
||||
private String reportId;
|
||||
|
||||
private String environmentId;
|
||||
|
||||
private List<String> scenarioIds;
|
||||
}
|
|
@ -3,6 +3,8 @@ package io.metersphere.api.dto.automation;
|
|||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class SaveApiScenarioRequest {
|
||||
|
@ -35,4 +37,6 @@ public class SaveApiScenarioRequest {
|
|||
private String description;
|
||||
|
||||
private String scenarioDefinition;
|
||||
|
||||
List<String> bodyUploadIds;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,9 @@ import com.alibaba.fastjson.JSON;
|
|||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.alibaba.fastjson.annotation.JSONType;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
import io.metersphere.api.service.ApiAutomationService;
|
||||
import io.metersphere.api.service.ApiTestEnvironmentService;
|
||||
|
@ -15,6 +18,7 @@ import lombok.EqualsAndHashCode;
|
|||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
|
@ -41,14 +45,21 @@ public class MsScenario extends MsTestElement {
|
|||
if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) {
|
||||
return;
|
||||
} else if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
|
||||
ApiAutomationService apiAutomationService = CommonBeanFactory.getBean(ApiAutomationService.class);
|
||||
ApiScenario scenario = apiAutomationService.getApiScenario(this.getId());
|
||||
JSONObject element = JSON.parseObject(scenario.getScenarioDefinition());
|
||||
List<MsTestElement> dataArr = JSON.parseArray(element.getString("hashTree"), MsTestElement.class);
|
||||
if (hashTree == null) {
|
||||
hashTree = dataArr;
|
||||
} else {
|
||||
hashTree.addAll(dataArr);
|
||||
try {
|
||||
ApiAutomationService apiAutomationService = CommonBeanFactory.getBean(ApiAutomationService.class);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
ApiScenario scenario = apiAutomationService.getApiScenario(this.getId());
|
||||
JSONObject element = JSON.parseObject(scenario.getScenarioDefinition());
|
||||
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
|
||||
});
|
||||
if (hashTree == null) {
|
||||
hashTree = elements;
|
||||
} else {
|
||||
hashTree.addAll(elements);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(hashTree)) {
|
||||
|
|
|
@ -51,7 +51,7 @@ import java.util.List;
|
|||
MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class,
|
||||
MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsScenario.class}, typeKey = "type")
|
||||
@Data
|
||||
public abstract class MsTestElement {
|
||||
public class MsTestElement {
|
||||
private String type;
|
||||
@JSONField(ordinal = 1)
|
||||
private String id;
|
||||
|
|
|
@ -50,4 +50,5 @@ public class MsThreadGroup extends MsTestElement {
|
|||
threadGroup.setSamplerController(loopController);
|
||||
return threadGroup;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
}
|
||||
} else if (StringUtils.equals(this.runMode, ApiRunMode.SCENARIO.name())) {
|
||||
// 执行报告不需要存储,由用户确认后在存储
|
||||
testResult.setTestId(debugReportId);
|
||||
testResult.setTestId(testId);
|
||||
apiScenarioReportService.complete(testResult);
|
||||
} else {
|
||||
apiTestService.changeStatus(testId, APITestStatus.Completed);
|
||||
|
|
|
@ -2,13 +2,16 @@ package io.metersphere.api.service;
|
|||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
import io.metersphere.api.dto.APIReportResult;
|
||||
import io.metersphere.api.dto.automation.ApiScenarioDTO;
|
||||
import io.metersphere.api.dto.automation.ApiScenarioRequest;
|
||||
import io.metersphere.api.dto.automation.SaveApiScenarioRequest;
|
||||
import io.metersphere.api.dto.automation.ScenarioStatus;
|
||||
import io.metersphere.api.dto.automation.*;
|
||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
||||
import io.metersphere.api.dto.definition.request.MsTestElement;
|
||||
import io.metersphere.api.dto.definition.request.MsTestPlan;
|
||||
import io.metersphere.api.dto.definition.request.MsThreadGroup;
|
||||
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
|
||||
import io.metersphere.api.jmeter.JMeterService;
|
||||
import io.metersphere.base.domain.*;
|
||||
|
@ -24,6 +27,7 @@ import io.metersphere.i18n.Translator;
|
|||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jorphan.collections.HashTree;
|
||||
import org.apache.jorphan.collections.ListedHashTree;
|
||||
import org.aspectj.util.FileUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
@ -32,9 +36,9 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
import javax.annotation.Resource;
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
|
@ -83,8 +87,9 @@ public class ApiAutomationService {
|
|||
apiScenarioMapper.deleteByExample(example);
|
||||
}
|
||||
|
||||
public void create(SaveApiScenarioRequest request) {
|
||||
public void create(SaveApiScenarioRequest request, List<MultipartFile> bodyFiles) {
|
||||
checkNameExist(request);
|
||||
|
||||
final ApiScenario scenario = new ApiScenario();
|
||||
scenario.setId(request.getId());
|
||||
scenario.setName(request.getName());
|
||||
|
@ -111,10 +116,16 @@ public class ApiAutomationService {
|
|||
}
|
||||
scenario.setDescription(request.getDescription());
|
||||
apiScenarioMapper.insert(scenario);
|
||||
|
||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||
createBodyFiles(bodyUploadIds, bodyFiles);
|
||||
}
|
||||
|
||||
public void update(SaveApiScenarioRequest request) {
|
||||
public void update(SaveApiScenarioRequest request, List<MultipartFile> bodyFiles) {
|
||||
checkNameExist(request);
|
||||
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
|
||||
createBodyFiles(bodyUploadIds, bodyFiles);
|
||||
|
||||
final ApiScenario scenario = new ApiScenario();
|
||||
scenario.setId(request.getId());
|
||||
scenario.setName(request.getName());
|
||||
|
@ -176,7 +187,7 @@ public class ApiAutomationService {
|
|||
}
|
||||
|
||||
private void createBodyFiles(List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
|
||||
if (!bodyUploadIds.isEmpty()) {
|
||||
if (!bodyUploadIds.isEmpty() && !bodyFiles.isEmpty()) {
|
||||
File testDir = new File(BODY_FILE_DIR);
|
||||
if (!testDir.exists()) {
|
||||
testDir.mkdirs();
|
||||
|
@ -208,6 +219,63 @@ public class ApiAutomationService {
|
|||
}
|
||||
}
|
||||
|
||||
private void createAPIReportResult(String id) {
|
||||
APIReportResult report = new APIReportResult();
|
||||
report.setId(id);
|
||||
report.setTestId(id);
|
||||
report.setName("");
|
||||
report.setTriggerMode(null);
|
||||
report.setCreateTime(System.currentTimeMillis());
|
||||
report.setUpdateTime(System.currentTimeMillis());
|
||||
report.setStatus(APITestStatus.Running.name());
|
||||
report.setUserId(SessionUtils.getUserId());
|
||||
apiReportService.addResult(report);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景测试执行
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public String run(RunScenarioRequest request) {
|
||||
List<ApiScenario> apiScenarios = extApiScenarioMapper.selectIds(request.getScenarioIds());
|
||||
MsTestPlan testPlan = new MsTestPlan();
|
||||
testPlan.setHashTree(new LinkedList<>());
|
||||
HashTree jmeterTestPlanHashTree = new ListedHashTree();
|
||||
EnvironmentConfig config = null;
|
||||
for (ApiScenario item : apiScenarios) {
|
||||
MsThreadGroup group = new MsThreadGroup();
|
||||
group.setLabel(item.getName());
|
||||
group.setName(item.getName());
|
||||
try {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
JSONObject element = JSON.parseObject(item.getScenarioDefinition());
|
||||
String environmentId = element.getString("environmentId");
|
||||
if (environmentId != null) {
|
||||
ApiTestEnvironmentWithBLOBs environment = environmentService.get(environmentId);
|
||||
config = JSONObject.parseObject(environment.getConfig(), EnvironmentConfig.class);
|
||||
}
|
||||
|
||||
LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
|
||||
});
|
||||
group.setHashTree(elements);
|
||||
testPlan.getHashTree().add(group);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
testPlan.toHashTree(jmeterTestPlanHashTree, testPlan.getHashTree(), config);
|
||||
|
||||
// 调用执行方法
|
||||
jMeterService.runDefinition(request.getId(), jmeterTestPlanHashTree, request.getReportId(), ApiRunMode.SCENARIO.name());
|
||||
createAPIReportResult(request.getId());
|
||||
return request.getId();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 场景测试执行
|
||||
*
|
||||
|
@ -228,17 +296,7 @@ public class ApiAutomationService {
|
|||
|
||||
// 调用执行方法
|
||||
jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), ApiRunMode.SCENARIO.name());
|
||||
APIReportResult report = new APIReportResult();
|
||||
report.setId(UUID.randomUUID().toString());
|
||||
report.setTestId(request.getReportId());
|
||||
report.setName("RUN");
|
||||
report.setTriggerMode(null);
|
||||
report.setCreateTime(System.currentTimeMillis());
|
||||
report.setUpdateTime(System.currentTimeMillis());
|
||||
report.setStatus(APITestStatus.Running.name());
|
||||
report.setUserId(SessionUtils.getUserId());
|
||||
apiReportService.addResult(report);
|
||||
createAPIReportResult(request.getId());
|
||||
return request.getId();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,23 +2,39 @@ package io.metersphere.api.service;
|
|||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.metersphere.api.dto.APIReportResult;
|
||||
import io.metersphere.api.dto.DeleteAPIReportRequest;
|
||||
import io.metersphere.api.dto.QueryAPIReportRequest;
|
||||
import io.metersphere.api.dto.automation.APIScenarioReportResult;
|
||||
import io.metersphere.api.jmeter.TestResult;
|
||||
import io.metersphere.base.domain.ApiTestReportDetail;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.ApiScenarioReportDetailMapper;
|
||||
import io.metersphere.base.mapper.ApiScenarioReportMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtApiScenarioReportMapper;
|
||||
import io.metersphere.commons.constants.APITestStatus;
|
||||
import io.metersphere.commons.exception.MSException;
|
||||
import io.metersphere.commons.utils.ServiceUtils;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import sun.security.util.Cache;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class ApiScenarioReportService {
|
||||
|
||||
private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24);
|
||||
@Resource
|
||||
private ExtApiScenarioReportMapper extApiScenarioReportMapper;
|
||||
@Resource
|
||||
private ApiScenarioReportMapper apiScenarioReportMapper;
|
||||
@Resource
|
||||
private ApiScenarioReportDetailMapper apiScenarioReportDetailMapper;
|
||||
|
||||
public void complete(TestResult result) {
|
||||
Object obj = cache.get(result.getTestId());
|
||||
|
@ -64,4 +80,103 @@ public class ApiScenarioReportService {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public APIReportResult get(String reportId) {
|
||||
APIReportResult reportResult = extApiScenarioReportMapper.get(reportId);
|
||||
ApiScenarioReportDetail detail = apiScenarioReportDetailMapper.selectByPrimaryKey(reportId);
|
||||
if (detail != null) {
|
||||
reportResult.setContent(new String(detail.getContent(), StandardCharsets.UTF_8));
|
||||
}
|
||||
return reportResult;
|
||||
}
|
||||
|
||||
public List<APIScenarioReportResult> list(QueryAPIReportRequest request) {
|
||||
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
|
||||
return extApiScenarioReportMapper.list(request);
|
||||
}
|
||||
|
||||
private void checkNameExist(APIScenarioReportResult request) {
|
||||
ApiScenarioReportExample example = new ApiScenarioReportExample();
|
||||
example.createCriteria().andNameEqualTo(request.getName()).andProjectIdEqualTo(request.getProjectId()).andIdNotEqualTo(request.getId());
|
||||
if (apiScenarioReportMapper.countByExample(example) > 0) {
|
||||
MSException.throwException(Translator.get("load_test_already_exists"));
|
||||
}
|
||||
}
|
||||
|
||||
public ApiScenarioReport createReport(APIScenarioReportResult test) {
|
||||
checkNameExist(test);
|
||||
ApiScenarioReport report = new ApiScenarioReport();
|
||||
report.setId(UUID.randomUUID().toString());
|
||||
report.setProjectId(test.getProjectId());
|
||||
report.setName(test.getName());
|
||||
report.setTriggerMode(test.getTriggerMode());
|
||||
report.setDescription(test.getDescription());
|
||||
report.setCreateTime(System.currentTimeMillis());
|
||||
report.setUpdateTime(System.currentTimeMillis());
|
||||
report.setStatus(test.getStatus());
|
||||
report.setUserId(test.getUserId());
|
||||
apiScenarioReportMapper.insert(report);
|
||||
return report;
|
||||
}
|
||||
|
||||
public ApiScenarioReport updateReport(APIScenarioReportResult test) {
|
||||
checkNameExist(test);
|
||||
ApiScenarioReport report = new ApiScenarioReport();
|
||||
report.setId(test.getId());
|
||||
report.setProjectId(test.getProjectId());
|
||||
report.setName(test.getName());
|
||||
report.setTriggerMode(test.getTriggerMode());
|
||||
report.setDescription(test.getDescription());
|
||||
report.setCreateTime(System.currentTimeMillis());
|
||||
report.setUpdateTime(System.currentTimeMillis());
|
||||
report.setStatus(test.getStatus());
|
||||
report.setUserId(test.getUserId());
|
||||
apiScenarioReportMapper.updateByPrimaryKey(report);
|
||||
return report;
|
||||
}
|
||||
|
||||
|
||||
public String add(APIScenarioReportResult test) {
|
||||
ApiScenarioReport report = createReport(test);
|
||||
ApiScenarioReportDetail detail = new ApiScenarioReportDetail();
|
||||
detail.setContent(test.getContent().getBytes(StandardCharsets.UTF_8));
|
||||
detail.setReportId(report.getId());
|
||||
detail.setProjectId(test.getProjectId());
|
||||
apiScenarioReportDetailMapper.insert(detail);
|
||||
return report.getId();
|
||||
}
|
||||
|
||||
public String update(APIScenarioReportResult test) {
|
||||
ApiScenarioReport report = updateReport(test);
|
||||
ApiScenarioReportDetail detail = apiScenarioReportDetailMapper.selectByPrimaryKey(test.getId());
|
||||
if (detail == null) {
|
||||
detail = new ApiScenarioReportDetail();
|
||||
detail.setContent(test.getContent().getBytes(StandardCharsets.UTF_8));
|
||||
detail.setReportId(report.getId());
|
||||
detail.setProjectId(test.getProjectId());
|
||||
apiScenarioReportDetailMapper.insert(detail);
|
||||
} else {
|
||||
detail.setContent(test.getContent().getBytes(StandardCharsets.UTF_8));
|
||||
detail.setReportId(report.getId());
|
||||
detail.setProjectId(test.getProjectId());
|
||||
apiScenarioReportDetailMapper.updateByPrimaryKey(detail);
|
||||
}
|
||||
return report.getId();
|
||||
}
|
||||
|
||||
public void delete(DeleteAPIReportRequest request) {
|
||||
apiScenarioReportDetailMapper.deleteByPrimaryKey(request.getId());
|
||||
apiScenarioReportMapper.deleteByPrimaryKey(request.getId());
|
||||
}
|
||||
|
||||
public void deleteAPIReportBatch(DeleteAPIReportRequest reportRequest) {
|
||||
ApiScenarioReportDetailExample detailExample = new ApiScenarioReportDetailExample();
|
||||
detailExample.createCriteria().andReportIdIn(reportRequest.getIds());
|
||||
apiScenarioReportDetailMapper.deleteByExample(detailExample);
|
||||
|
||||
ApiScenarioReportExample apiTestReportExample = new ApiScenarioReportExample();
|
||||
apiTestReportExample.createCriteria().andIdIn(reportRequest.getIds());
|
||||
apiScenarioReportMapper.deleteByExample(apiTestReportExample);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package io.metersphere.base.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class ApiScenarioReport implements Serializable {
|
||||
private String id;
|
||||
|
||||
private String scenarioId;
|
||||
private String projectId;
|
||||
|
||||
private String name;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import lombok.Data;
|
|||
public class ApiScenarioReportDetail implements Serializable {
|
||||
private String reportId;
|
||||
|
||||
private String scenarioId;
|
||||
private String projectId;
|
||||
|
||||
private byte[] content;
|
||||
|
||||
|
|
|
@ -174,73 +174,73 @@ public class ApiScenarioReportDetailExample {
|
|||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdIsNull() {
|
||||
addCriterion("scenario_id is null");
|
||||
public Criteria andProjectIdIsNull() {
|
||||
addCriterion("project_id is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdIsNotNull() {
|
||||
addCriterion("scenario_id is not null");
|
||||
public Criteria andProjectIdIsNotNull() {
|
||||
addCriterion("project_id is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdEqualTo(String value) {
|
||||
addCriterion("scenario_id =", value, "scenarioId");
|
||||
public Criteria andProjectIdEqualTo(String value) {
|
||||
addCriterion("project_id =", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotEqualTo(String value) {
|
||||
addCriterion("scenario_id <>", value, "scenarioId");
|
||||
public Criteria andProjectIdNotEqualTo(String value) {
|
||||
addCriterion("project_id <>", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdGreaterThan(String value) {
|
||||
addCriterion("scenario_id >", value, "scenarioId");
|
||||
public Criteria andProjectIdGreaterThan(String value) {
|
||||
addCriterion("project_id >", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("scenario_id >=", value, "scenarioId");
|
||||
public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("project_id >=", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdLessThan(String value) {
|
||||
addCriterion("scenario_id <", value, "scenarioId");
|
||||
public Criteria andProjectIdLessThan(String value) {
|
||||
addCriterion("project_id <", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdLessThanOrEqualTo(String value) {
|
||||
addCriterion("scenario_id <=", value, "scenarioId");
|
||||
public Criteria andProjectIdLessThanOrEqualTo(String value) {
|
||||
addCriterion("project_id <=", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdLike(String value) {
|
||||
addCriterion("scenario_id like", value, "scenarioId");
|
||||
public Criteria andProjectIdLike(String value) {
|
||||
addCriterion("project_id like", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotLike(String value) {
|
||||
addCriterion("scenario_id not like", value, "scenarioId");
|
||||
public Criteria andProjectIdNotLike(String value) {
|
||||
addCriterion("project_id not like", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdIn(List<String> values) {
|
||||
addCriterion("scenario_id in", values, "scenarioId");
|
||||
public Criteria andProjectIdIn(List<String> values) {
|
||||
addCriterion("project_id in", values, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotIn(List<String> values) {
|
||||
addCriterion("scenario_id not in", values, "scenarioId");
|
||||
public Criteria andProjectIdNotIn(List<String> values) {
|
||||
addCriterion("project_id not in", values, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdBetween(String value1, String value2) {
|
||||
addCriterion("scenario_id between", value1, value2, "scenarioId");
|
||||
public Criteria andProjectIdBetween(String value1, String value2) {
|
||||
addCriterion("project_id between", value1, value2, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotBetween(String value1, String value2) {
|
||||
addCriterion("scenario_id not between", value1, value2, "scenarioId");
|
||||
public Criteria andProjectIdNotBetween(String value1, String value2) {
|
||||
addCriterion("project_id not between", value1, value2, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,73 +174,73 @@ public class ApiScenarioReportExample {
|
|||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdIsNull() {
|
||||
addCriterion("scenario_id is null");
|
||||
public Criteria andProjectIdIsNull() {
|
||||
addCriterion("project_id is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdIsNotNull() {
|
||||
addCriterion("scenario_id is not null");
|
||||
public Criteria andProjectIdIsNotNull() {
|
||||
addCriterion("project_id is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdEqualTo(String value) {
|
||||
addCriterion("scenario_id =", value, "scenarioId");
|
||||
public Criteria andProjectIdEqualTo(String value) {
|
||||
addCriterion("project_id =", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotEqualTo(String value) {
|
||||
addCriterion("scenario_id <>", value, "scenarioId");
|
||||
public Criteria andProjectIdNotEqualTo(String value) {
|
||||
addCriterion("project_id <>", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdGreaterThan(String value) {
|
||||
addCriterion("scenario_id >", value, "scenarioId");
|
||||
public Criteria andProjectIdGreaterThan(String value) {
|
||||
addCriterion("project_id >", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("scenario_id >=", value, "scenarioId");
|
||||
public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("project_id >=", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdLessThan(String value) {
|
||||
addCriterion("scenario_id <", value, "scenarioId");
|
||||
public Criteria andProjectIdLessThan(String value) {
|
||||
addCriterion("project_id <", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdLessThanOrEqualTo(String value) {
|
||||
addCriterion("scenario_id <=", value, "scenarioId");
|
||||
public Criteria andProjectIdLessThanOrEqualTo(String value) {
|
||||
addCriterion("project_id <=", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdLike(String value) {
|
||||
addCriterion("scenario_id like", value, "scenarioId");
|
||||
public Criteria andProjectIdLike(String value) {
|
||||
addCriterion("project_id like", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotLike(String value) {
|
||||
addCriterion("scenario_id not like", value, "scenarioId");
|
||||
public Criteria andProjectIdNotLike(String value) {
|
||||
addCriterion("project_id not like", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdIn(List<String> values) {
|
||||
addCriterion("scenario_id in", values, "scenarioId");
|
||||
public Criteria andProjectIdIn(List<String> values) {
|
||||
addCriterion("project_id in", values, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotIn(List<String> values) {
|
||||
addCriterion("scenario_id not in", values, "scenarioId");
|
||||
public Criteria andProjectIdNotIn(List<String> values) {
|
||||
addCriterion("project_id not in", values, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdBetween(String value1, String value2) {
|
||||
addCriterion("scenario_id between", value1, value2, "scenarioId");
|
||||
public Criteria andProjectIdBetween(String value1, String value2) {
|
||||
addCriterion("project_id between", value1, value2, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andScenarioIdNotBetween(String value1, String value2) {
|
||||
addCriterion("scenario_id not between", value1, value2, "scenarioId");
|
||||
public Criteria andProjectIdNotBetween(String value1, String value2) {
|
||||
addCriterion("project_id not between", value1, value2, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<mapper namespace="io.metersphere.base.mapper.ApiScenarioReportDetailMapper">
|
||||
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiScenarioReportDetail">
|
||||
<id column="report_id" jdbcType="VARCHAR" property="reportId" />
|
||||
<result column="scenario_id" jdbcType="VARCHAR" property="scenarioId" />
|
||||
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
|
||||
</resultMap>
|
||||
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenarioReportDetail">
|
||||
<result column="content" jdbcType="LONGVARBINARY" property="content" />
|
||||
|
@ -67,7 +67,7 @@
|
|||
</where>
|
||||
</sql>
|
||||
<sql id="Base_Column_List">
|
||||
report_id, scenario_id
|
||||
report_id, project_id
|
||||
</sql>
|
||||
<sql id="Blob_Column_List">
|
||||
content
|
||||
|
@ -121,9 +121,9 @@
|
|||
</if>
|
||||
</delete>
|
||||
<insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
|
||||
insert into api_scenario_report_detail (report_id, scenario_id, content
|
||||
insert into api_scenario_report_detail (report_id, project_id, content
|
||||
)
|
||||
values (#{reportId,jdbcType=VARCHAR}, #{scenarioId,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARBINARY}
|
||||
values (#{reportId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{content,jdbcType=LONGVARBINARY}
|
||||
)
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
|
||||
|
@ -132,8 +132,8 @@
|
|||
<if test="reportId != null">
|
||||
report_id,
|
||||
</if>
|
||||
<if test="scenarioId != null">
|
||||
scenario_id,
|
||||
<if test="projectId != null">
|
||||
project_id,
|
||||
</if>
|
||||
<if test="content != null">
|
||||
content,
|
||||
|
@ -143,8 +143,8 @@
|
|||
<if test="reportId != null">
|
||||
#{reportId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="scenarioId != null">
|
||||
#{scenarioId,jdbcType=VARCHAR},
|
||||
<if test="projectId != null">
|
||||
#{projectId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="content != null">
|
||||
#{content,jdbcType=LONGVARBINARY},
|
||||
|
@ -163,8 +163,8 @@
|
|||
<if test="record.reportId != null">
|
||||
report_id = #{record.reportId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.scenarioId != null">
|
||||
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
|
||||
<if test="record.projectId != null">
|
||||
project_id = #{record.projectId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.content != null">
|
||||
content = #{record.content,jdbcType=LONGVARBINARY},
|
||||
|
@ -177,7 +177,7 @@
|
|||
<update id="updateByExampleWithBLOBs" parameterType="map">
|
||||
update api_scenario_report_detail
|
||||
set report_id = #{record.reportId,jdbcType=VARCHAR},
|
||||
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
|
||||
project_id = #{record.projectId,jdbcType=VARCHAR},
|
||||
content = #{record.content,jdbcType=LONGVARBINARY}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
|
@ -186,7 +186,7 @@
|
|||
<update id="updateByExample" parameterType="map">
|
||||
update api_scenario_report_detail
|
||||
set report_id = #{record.reportId,jdbcType=VARCHAR},
|
||||
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}
|
||||
project_id = #{record.projectId,jdbcType=VARCHAR}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
|
@ -194,8 +194,8 @@
|
|||
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
|
||||
update api_scenario_report_detail
|
||||
<set>
|
||||
<if test="scenarioId != null">
|
||||
scenario_id = #{scenarioId,jdbcType=VARCHAR},
|
||||
<if test="projectId != null">
|
||||
project_id = #{projectId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="content != null">
|
||||
content = #{content,jdbcType=LONGVARBINARY},
|
||||
|
@ -205,13 +205,13 @@
|
|||
</update>
|
||||
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
|
||||
update api_scenario_report_detail
|
||||
set scenario_id = #{scenarioId,jdbcType=VARCHAR},
|
||||
set project_id = #{projectId,jdbcType=VARCHAR},
|
||||
content = #{content,jdbcType=LONGVARBINARY}
|
||||
where report_id = #{reportId,jdbcType=VARCHAR}
|
||||
</update>
|
||||
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
|
||||
update api_scenario_report_detail
|
||||
set scenario_id = #{scenarioId,jdbcType=VARCHAR}
|
||||
set project_id = #{projectId,jdbcType=VARCHAR}
|
||||
where report_id = #{reportId,jdbcType=VARCHAR}
|
||||
</update>
|
||||
</mapper>
|
|
@ -3,7 +3,7 @@
|
|||
<mapper namespace="io.metersphere.base.mapper.ApiScenarioReportMapper">
|
||||
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiScenarioReport">
|
||||
<id column="id" jdbcType="VARCHAR" property="id" />
|
||||
<result column="scenario_id" jdbcType="VARCHAR" property="scenarioId" />
|
||||
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
|
||||
<result column="name" jdbcType="VARCHAR" property="name" />
|
||||
<result column="description" jdbcType="VARCHAR" property="description" />
|
||||
<result column="create_time" jdbcType="BIGINT" property="createTime" />
|
||||
|
@ -71,7 +71,7 @@
|
|||
</where>
|
||||
</sql>
|
||||
<sql id="Base_Column_List">
|
||||
id, scenario_id, `name`, description, create_time, update_time, `status`, user_id,
|
||||
id, project_id, `name`, description, create_time, update_time, `status`, user_id,
|
||||
trigger_mode
|
||||
</sql>
|
||||
<select id="selectByExample" parameterType="io.metersphere.base.domain.ApiScenarioReportExample" resultMap="BaseResultMap">
|
||||
|
@ -105,11 +105,11 @@
|
|||
</if>
|
||||
</delete>
|
||||
<insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReport">
|
||||
insert into api_scenario_report (id, scenario_id, `name`,
|
||||
insert into api_scenario_report (id, project_id, `name`,
|
||||
description, create_time, update_time,
|
||||
`status`, user_id, trigger_mode
|
||||
)
|
||||
values (#{id,jdbcType=VARCHAR}, #{scenarioId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
|
||||
values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
|
||||
#{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
|
||||
#{status,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR}
|
||||
)
|
||||
|
@ -120,8 +120,8 @@
|
|||
<if test="id != null">
|
||||
id,
|
||||
</if>
|
||||
<if test="scenarioId != null">
|
||||
scenario_id,
|
||||
<if test="projectId != null">
|
||||
project_id,
|
||||
</if>
|
||||
<if test="name != null">
|
||||
`name`,
|
||||
|
@ -149,8 +149,8 @@
|
|||
<if test="id != null">
|
||||
#{id,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="scenarioId != null">
|
||||
#{scenarioId,jdbcType=VARCHAR},
|
||||
<if test="projectId != null">
|
||||
#{projectId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="name != null">
|
||||
#{name,jdbcType=VARCHAR},
|
||||
|
@ -187,8 +187,8 @@
|
|||
<if test="record.id != null">
|
||||
id = #{record.id,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.scenarioId != null">
|
||||
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
|
||||
<if test="record.projectId != null">
|
||||
project_id = #{record.projectId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.name != null">
|
||||
`name` = #{record.name,jdbcType=VARCHAR},
|
||||
|
@ -219,7 +219,7 @@
|
|||
<update id="updateByExample" parameterType="map">
|
||||
update api_scenario_report
|
||||
set id = #{record.id,jdbcType=VARCHAR},
|
||||
scenario_id = #{record.scenarioId,jdbcType=VARCHAR},
|
||||
project_id = #{record.projectId,jdbcType=VARCHAR},
|
||||
`name` = #{record.name,jdbcType=VARCHAR},
|
||||
description = #{record.description,jdbcType=VARCHAR},
|
||||
create_time = #{record.createTime,jdbcType=BIGINT},
|
||||
|
@ -234,8 +234,8 @@
|
|||
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReport">
|
||||
update api_scenario_report
|
||||
<set>
|
||||
<if test="scenarioId != null">
|
||||
scenario_id = #{scenarioId,jdbcType=VARCHAR},
|
||||
<if test="projectId != null">
|
||||
project_id = #{projectId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="name != null">
|
||||
`name` = #{name,jdbcType=VARCHAR},
|
||||
|
@ -263,7 +263,7 @@
|
|||
</update>
|
||||
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenarioReport">
|
||||
update api_scenario_report
|
||||
set scenario_id = #{scenarioId,jdbcType=VARCHAR},
|
||||
set project_id = #{projectId,jdbcType=VARCHAR},
|
||||
`name` = #{name,jdbcType=VARCHAR},
|
||||
description = #{description,jdbcType=VARCHAR},
|
||||
create_time = #{createTime,jdbcType=BIGINT},
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package io.metersphere.base.mapper.ext;
|
||||
|
||||
import io.metersphere.api.dto.APIReportResult;
|
||||
import io.metersphere.api.dto.QueryAPIReportRequest;
|
||||
import io.metersphere.api.dto.automation.APIScenarioReportResult;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ExtApiScenarioReportMapper {
|
||||
List<APIScenarioReportResult> list(@Param("request") QueryAPIReportRequest request);
|
||||
|
||||
APIReportResult get(@Param("reportId") String reportId);
|
||||
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="io.metersphere.base.mapper.ext.ExtApiScenarioReportMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="io.metersphere.api.dto.automation.APIScenarioReportResult"
|
||||
extends="io.metersphere.base.mapper.ApiScenarioReportMapper.BaseResultMap">
|
||||
<result column="test_name" property="testName"/>
|
||||
<result column="project_name" property="projectName"/>
|
||||
<result column="user_name" property="userName"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="condition">
|
||||
<choose>
|
||||
<when test='${object}.operator == "like"'>
|
||||
like CONCAT('%', #{${object}.value},'%')
|
||||
</when>
|
||||
<when test='${object}.operator == "not like"'>
|
||||
not like CONCAT('%', #{${object}.value},'%')
|
||||
</when>
|
||||
<when test='${object}.operator == "in"'>
|
||||
in
|
||||
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
|
||||
#{v}
|
||||
</foreach>
|
||||
</when>
|
||||
<when test='${object}.operator == "not in"'>
|
||||
not in
|
||||
<foreach collection="${object}.value" item="v" separator="," open="(" close=")">
|
||||
#{v}
|
||||
</foreach>
|
||||
</when>
|
||||
<when test='${object}.operator == "between"'>
|
||||
between #{${object}.value[0]} and #{${object}.value[1]}
|
||||
</when>
|
||||
<when test='${object}.operator == "gt"'>
|
||||
> #{${object}.value}
|
||||
</when>
|
||||
<when test='${object}.operator == "lt"'>
|
||||
< #{${object}.value}
|
||||
</when>
|
||||
<when test='${object}.operator == "ge"'>
|
||||
>= #{${object}.value}
|
||||
</when>
|
||||
<when test='${object}.operator == "le"'>
|
||||
<= #{${object}.value}
|
||||
</when>
|
||||
<when test='${object}.operator == "current user"'>
|
||||
= '${@io.metersphere.commons.utils.SessionUtils@getUserId()}'
|
||||
</when>
|
||||
<otherwise>
|
||||
= #{${object}.value}
|
||||
</otherwise>
|
||||
</choose>
|
||||
</sql>
|
||||
|
||||
<sql id="combine">
|
||||
<if test='${condition}.name != null and (${name} == null or ${name} == "")'>
|
||||
and r.name
|
||||
<include refid="condition">
|
||||
<property name="object" value="${condition}.name"/>
|
||||
</include>
|
||||
</if>
|
||||
<if test="${condition}.testName != null">
|
||||
and t.name
|
||||
<include refid="condition">
|
||||
<property name="object" value="${condition}.testName"/>
|
||||
</include>
|
||||
</if>
|
||||
<if test="${condition}.projectName != null">
|
||||
and project.name
|
||||
<include refid="condition">
|
||||
<property name="object" value="${condition}.projectName"/>
|
||||
</include>
|
||||
</if>
|
||||
<if test="${condition}.createTime != null">
|
||||
and r.create_time
|
||||
<include refid="condition">
|
||||
<property name="object" value="${condition}.createTime"/>
|
||||
</include>
|
||||
</if>
|
||||
<if test="${condition}.status != null">
|
||||
and r.status
|
||||
<include refid="condition">
|
||||
<property name="object" value="${condition}.status"/>
|
||||
</include>
|
||||
</if>
|
||||
<if test="${condition}.triggerMode != null">
|
||||
and r.trigger_mode
|
||||
<include refid="condition">
|
||||
<property name="object" value="${condition}.triggerMode"/>
|
||||
</include>
|
||||
</if>
|
||||
<if test="${condition}.creator != null">
|
||||
and r.user_id
|
||||
<include refid="condition">
|
||||
<property name="object" value="${condition}.creator"/>
|
||||
</include>
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<select id="list" resultMap="BaseResultMap">
|
||||
SELECT r.name AS test_name,
|
||||
r.name, r.description, r.id, r.project_id, r.create_time, r.update_time, r.status, r.trigger_mode,
|
||||
project.name AS project_name, user.name AS user_name
|
||||
FROM api_scenario_report r
|
||||
LEFT JOIN project ON project.id = r.project_id
|
||||
LEFT JOIN user ON user.id = r.user_id
|
||||
<where>
|
||||
<if test="request.combine != null">
|
||||
<include refid="combine">
|
||||
<property name="condition" value="request.combine"/>
|
||||
<property name="name" value="request.name"/>
|
||||
</include>
|
||||
</if>
|
||||
|
||||
<if test="request.name != null">
|
||||
and r.name like CONCAT('%', #{request.name},'%')
|
||||
</if>
|
||||
<if test="request.userId != null">
|
||||
AND r.user_id = #{request.userId,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="request.projectId != null">
|
||||
AND project.id = #{request.projectId}
|
||||
</if>
|
||||
<if test="request.workspaceId != null">
|
||||
AND project.workspace_id = #{request.workspaceId,jdbcType=VARCHAR}
|
||||
</if>
|
||||
<if test="request.filters != null and request.filters.size() > 0">
|
||||
<foreach collection="request.filters.entrySet()" index="key" item="values">
|
||||
<if test="values != null and values.size() > 0">
|
||||
<choose>
|
||||
<when test="key=='status'">
|
||||
and r.status in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</when>
|
||||
<otherwise>
|
||||
and r.trigger_mode in
|
||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
</otherwise>
|
||||
</choose>
|
||||
</if>
|
||||
</foreach>
|
||||
</if>
|
||||
AND r.status != 'Debug'
|
||||
</where>
|
||||
<if test="request.orders != null and request.orders.size() > 0">
|
||||
order by
|
||||
<foreach collection="request.orders" separator="," item="order">
|
||||
r.${order.name} ${order.type}
|
||||
</foreach>
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="get" resultType="io.metersphere.api.dto.APIReportResult">
|
||||
SELECT r.*,r.id As testId, r.name AS test_name, project.name AS project_name, user.name AS user_name
|
||||
FROM api_scenario_report r
|
||||
LEFT JOIN project ON project.id = r.project_id
|
||||
LEFT JOIN user ON user.id = r.user_id
|
||||
<where>
|
||||
r.id = #{reportId}
|
||||
</where>
|
||||
ORDER BY r.update_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -83,4 +83,10 @@ public class ProjectController {
|
|||
public void updateProject(@RequestBody Project Project) {
|
||||
projectService.updateProject(Project);
|
||||
}
|
||||
|
||||
@PostMapping("/search")
|
||||
public List<ProjectDTO> searchProject(@RequestBody ProjectRequest projectRequest) {
|
||||
projectRequest.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
||||
return projectService.getProjectList(projectRequest);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,10 +64,8 @@
|
|||
|
||||
<!--要生成的数据库表 -->
|
||||
|
||||
<table tableName="schedule"/>
|
||||
<table tableName="notice"/>
|
||||
<table tableName="message_task"/>
|
||||
<table tableName="test_plan"/>
|
||||
<table tableName="api_scenario_report"/>
|
||||
<table tableName="api_scenario_report_detail"/>
|
||||
|
||||
</context>
|
||||
</generatorConfiguration>
|
|
@ -4,12 +4,12 @@
|
|||
<el-card>
|
||||
<section class="report-container" v-if="this.report.testId">
|
||||
|
||||
<ms-api-report-view-header :report="report" @reportExport="handleExport"/>
|
||||
<ms-api-report-view-header :report="report" @reportExport="handleExport" @reportSave="handleSave"/>
|
||||
|
||||
<main v-if="this.isNotRunning">
|
||||
<ms-metric-chart :content="content" :totalTime="totalTime"/>
|
||||
<div @click="active">
|
||||
<ms-scenario-results :scenarios="content.scenarios" v-on:requestResult="requestResult"/>
|
||||
<div>
|
||||
<ms-scenario-results :scenarios="content.scenarios" v-on:requestResult="requestResult"/>
|
||||
</div>
|
||||
<el-collapse-transition>
|
||||
<div v-show="isActive" style="width: 99%">
|
||||
|
@ -64,10 +64,14 @@
|
|||
requestType: undefined,
|
||||
}
|
||||
},
|
||||
props: ['reportId'],
|
||||
activated() {
|
||||
this.isRequestResult = false;
|
||||
},
|
||||
props: {
|
||||
reportId: String,
|
||||
currentProjectId: String,
|
||||
infoDb: Boolean,
|
||||
},
|
||||
watch: {
|
||||
reportId() {
|
||||
this.getReport();
|
||||
|
@ -91,7 +95,7 @@
|
|||
getReport() {
|
||||
this.init();
|
||||
if (this.reportId) {
|
||||
let url = "/api/scenario/report/get/" + this.reportId;
|
||||
let url = "/api/scenario/report/get/" + this.reportId + "/" + this.infoDb;
|
||||
this.$get(url, response => {
|
||||
this.report = response.data || {};
|
||||
if (response.data) {
|
||||
|
@ -99,7 +103,6 @@
|
|||
try {
|
||||
this.content = JSON.parse(this.report.content);
|
||||
} catch (e) {
|
||||
// console.log(this.report.content)
|
||||
throw e;
|
||||
}
|
||||
this.getFails();
|
||||
|
@ -136,6 +139,7 @@
|
|||
}
|
||||
},
|
||||
requestResult(requestResult) {
|
||||
this.active();
|
||||
this.isRequestResult = false;
|
||||
this.requestType = undefined;
|
||||
if (requestResult.request.body.indexOf('[Callable Statement]') > -1) {
|
||||
|
@ -155,6 +159,27 @@
|
|||
reset();
|
||||
});
|
||||
},
|
||||
handleSave() {
|
||||
if (!this.report.name) {
|
||||
this.$warning(this.$t('api_test.automation.report_name_info'));
|
||||
return;
|
||||
}
|
||||
if (!this.currentProjectId) {
|
||||
this.$warning(this.$t('api_test.select_project'));
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.report.projectId = this.currentProjectId;
|
||||
let url = "/api/scenario/report/add";
|
||||
if (this.infoDb === true) {
|
||||
url = "/api/scenario/report/update";
|
||||
}
|
||||
this.result = this.$post(url, this.report, response => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.loading = false;
|
||||
this.$emit('refresh');
|
||||
});
|
||||
},
|
||||
exportReportReset() {
|
||||
this.$router.go(0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
<template>
|
||||
<ms-container>
|
||||
<ms-main-container>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<ms-table-header :is-tester-permission="true" :condition.sync="condition" @search="search"
|
||||
:title="$t('api_report.title')"
|
||||
:show-create="false"/>
|
||||
</template>
|
||||
<el-table border :data="tableData" class="adjust-table table-content" @sort-change="sort"
|
||||
@select-all="handleSelectAll"
|
||||
@select="handleSelect"
|
||||
@filter-change="filter" @row-click="handleView">
|
||||
<el-table-column
|
||||
type="selection"/>
|
||||
<el-table-column width="40" :resizable="false" align="center">
|
||||
<template v-slot:default="scope">
|
||||
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectRows.size"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.name')" width="200" show-overflow-tooltip prop="name">
|
||||
</el-table-column>
|
||||
<!--
|
||||
<el-table-column prop="testName" :label="$t('api_report.test_name')" width="200" show-overflow-tooltip/>
|
||||
-->
|
||||
<el-table-column prop="projectName" :label="$t('load_test.project_name')" width="150" show-overflow-tooltip/>
|
||||
<el-table-column prop="userName" :label="$t('api_test.creator')" width="150" show-overflow-tooltip/>
|
||||
<el-table-column prop="createTime" width="250" :label="$t('commons.create_time')" sortable>
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="triggerMode" width="150" :label="$t('commons.trigger_mode.name')"
|
||||
column-key="triggerMode" :filters="triggerFilters">
|
||||
<template v-slot:default="scope">
|
||||
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" :label="$t('commons.status')"
|
||||
column-key="status"
|
||||
:filters="statusFilters">
|
||||
<template v-slot:default="{row}">
|
||||
<ms-api-report-status :row="row"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column width="150" :label="$t('commons.operating')">
|
||||
<template v-slot:default="scope">
|
||||
<ms-table-operator-button :tip="$t('api_report.detail')" icon="el-icon-s-data"
|
||||
@exec="handleView(scope.row)" type="primary"/>
|
||||
<ms-table-operator-button :is-tester-permission="true" :tip="$t('api_report.delete')"
|
||||
icon="el-icon-delete" @exec="handleDelete(scope.row)" type="danger"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
|
||||
:total="total"/>
|
||||
</el-card>
|
||||
</ms-main-container>
|
||||
|
||||
<el-drawer :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
|
||||
<ms-api-report-detail :report-id="reportId" :currentProjectId="currentProjectId" :info-db="true" @refresh="search"/>
|
||||
</el-drawer>
|
||||
</ms-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsTablePagination from "../../../common/pagination/TablePagination";
|
||||
import MsTableHeader from "../../../common/components/MsTableHeader";
|
||||
import MsContainer from "../../../common/components/MsContainer";
|
||||
import MsMainContainer from "../../../common/components/MsMainContainer";
|
||||
import MsApiReportStatus from "./ApiReportStatus";
|
||||
import {_filter, _sort} from "@/common/js/utils";
|
||||
import MsTableOperatorButton from "../../../common/components/MsTableOperatorButton";
|
||||
import ReportTriggerModeItem from "../../../common/tableItem/ReportTriggerModeItem";
|
||||
import {REPORT_CONFIGS} from "../../../common/components/search/search-components";
|
||||
import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent";
|
||||
import ShowMoreBtn from "../../../track/case/components/ShowMoreBtn";
|
||||
import MsApiReportDetail from "./ApiReportDetail";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ReportTriggerModeItem,
|
||||
MsTableOperatorButton,
|
||||
MsApiReportStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination, ShowMoreBtn, MsApiReportDetail
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
reportId: "",
|
||||
debugVisible: false,
|
||||
condition: {
|
||||
components: REPORT_CONFIGS
|
||||
},
|
||||
tableData: [],
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
total: 0,
|
||||
loading: false,
|
||||
currentProjectId: "",
|
||||
statusFilters: [
|
||||
{text: 'Saved', value: 'Saved'},
|
||||
{text: 'Starting', value: 'Starting'},
|
||||
{text: 'Running', value: 'Running'},
|
||||
{text: 'Reporting', value: 'Reporting'},
|
||||
{text: 'Completed', value: 'Completed'},
|
||||
{text: 'Error', value: 'Error'},
|
||||
{text: 'Success', value: 'Success'},
|
||||
],
|
||||
triggerFilters: [
|
||||
{text: this.$t('commons.trigger_mode.manual'), value: 'MANUAL'},
|
||||
{text: this.$t('commons.trigger_mode.schedule'), value: 'SCHEDULE'},
|
||||
{text: this.$t('commons.trigger_mode.api'), value: 'API'}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
name: this.$t('api_report.batch_delete'), handleClick: this.handleBatchDelete
|
||||
}
|
||||
],
|
||||
selectRows: new Set(),
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$route': 'init',
|
||||
},
|
||||
|
||||
methods: {
|
||||
search() {
|
||||
if (this.testId !== 'all') {
|
||||
this.condition.testId = this.testId;
|
||||
}
|
||||
let url = "/api/scenario/report/list/" + this.currentPage + "/" + this.pageSize;
|
||||
this.result = this.$post(url, this.condition, response => {
|
||||
let data = response.data;
|
||||
this.total = data.itemCount;
|
||||
this.tableData = data.listObject;
|
||||
this.selectRows.clear();
|
||||
});
|
||||
},
|
||||
handleSelectionChange(val) {
|
||||
this.multipleSelection = val;
|
||||
},
|
||||
handleView(report) {
|
||||
this.reportId = report.id;
|
||||
this.currentProjectId = report.projectId;
|
||||
this.debugVisible = true;
|
||||
},
|
||||
handleDelete(report) {
|
||||
this.$alert(this.$t('api_report.delete_confirm') + report.name + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
this.result = this.$post("/api/scenario/report/delete", {id: report.id}, () => {
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
this.search();
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
ApiEvent.$emit(LIST_CHANGE);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
init() {
|
||||
this.testId = this.$route.params.testId;
|
||||
this.search();
|
||||
},
|
||||
sort(column) {
|
||||
_sort(column, this.condition);
|
||||
this.init();
|
||||
},
|
||||
filter(filters) {
|
||||
_filter(filters, this.condition);
|
||||
this.init();
|
||||
},
|
||||
handleSelect(selection, row) {
|
||||
if (this.selectRows.has(row)) {
|
||||
this.$set(row, "showMore", false);
|
||||
this.selectRows.delete(row);
|
||||
} else {
|
||||
this.$set(row, "showMore", true);
|
||||
this.selectRows.add(row);
|
||||
}
|
||||
},
|
||||
handleSelectAll(selection) {
|
||||
if (selection.length > 0) {
|
||||
this.tableData.forEach(item => {
|
||||
this.$set(item, "showMore", true);
|
||||
this.selectRows.add(item);
|
||||
});
|
||||
} else {
|
||||
this.selectRows.clear();
|
||||
this.tableData.forEach(row => {
|
||||
this.$set(row, "showMore", false);
|
||||
})
|
||||
}
|
||||
},
|
||||
handleBatchDelete() {
|
||||
this.$alert(this.$t('api_report.delete_batch_confirm') + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
this.$post('/api/scenario/report/batch/delete', {ids: ids}, () => {
|
||||
this.selectRows.clear();
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
this.search();
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
ApiEvent.$emit(LIST_CHANGE);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
created() {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.table-content {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
|
@ -2,13 +2,17 @@
|
|||
<header class="report-header">
|
||||
<el-row>
|
||||
<el-col>
|
||||
<span>{{ report.projectName === null || report.projectName ==='' ? "场景执行报告": report.projectName}} / </span>
|
||||
<router-link :to="path">{{ report.testName }}</router-link>
|
||||
<span><el-input size="mini" style="width: 200px" v-model="report.name"/> </span>
|
||||
<span class="time"> {{ report.createTime | timestampFormatDate }}</span>
|
||||
<el-button :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleExport(report.name)"
|
||||
style="margin-left: 1200px">
|
||||
|
||||
<el-button :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleExport(report.name)" style="margin-right: 10px">
|
||||
{{$t('test_track.plan_view.export_report')}}
|
||||
</el-button>
|
||||
|
||||
<el-button :disabled="isReadOnly" class="export-button" plain type="primary" size="mini" @click="handleSave(report.name)" style="margin-right: 10px">
|
||||
{{$t('commons.save')}}
|
||||
</el-button>
|
||||
|
||||
</el-col>
|
||||
</el-row>
|
||||
</header>
|
||||
|
@ -38,6 +42,9 @@
|
|||
methods: {
|
||||
handleExport(name) {
|
||||
this.$emit('reportExport', name);
|
||||
},
|
||||
handleSave(name) {
|
||||
this.$emit('reportSave', name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,24 @@
|
|||
<template>
|
||||
<div class="scenario-result">
|
||||
<div v-for="(request, index) in scenario.requestResults" :key="index">
|
||||
<ms-request-result :key="index" :request="request" :indexNumber="index"
|
||||
v-on:requestResult="requestResult"
|
||||
:scenarioName="scenario.name"/>
|
||||
|
||||
<div @click="active">
|
||||
<el-row :gutter="10" type="flex" align="middle" class="info">
|
||||
<el-col :span="16">
|
||||
<i class="icon el-icon-arrow-right" :class="{'is-active': isActive}"/>
|
||||
{{scenario.name}}
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-collapse-transition>
|
||||
<div v-show="isActive">
|
||||
<div v-for="(request, index) in scenario.requestResults" :key="index">
|
||||
<ms-request-result :key="index" :request="request" :indexNumber="index"
|
||||
v-on:requestResult="requestResult"
|
||||
:scenarioName="scenario.name"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</el-collapse-transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,62 +1,72 @@
|
|||
<template>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<ms-table-header :condition.sync="condition" @search="search" title=""
|
||||
:show-create="false"/>
|
||||
</template>
|
||||
<div>
|
||||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<ms-table-header :condition.sync="condition" @search="search" title=""
|
||||
:show-create="false"/>
|
||||
</template>
|
||||
|
||||
<el-table ref="scenarioTable" border :data="tableData" class="adjust-table" @select-all="select" @select="select">
|
||||
<el-table-column type="selection"/>
|
||||
<el-table-column width="40" :resizable="false" align="center">
|
||||
<template v-slot:default="{row}">
|
||||
<show-more-btn :is-show="isSelect(row)" :buttons="buttons" :size="selection.length"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" :label="$t('api_test.automation.scenario_name')"
|
||||
show-overflow-tooltip/>
|
||||
<el-table-column prop="level" :label="$t('api_test.automation.case_level')"
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<ms-tag v-if="scope.row.level == 'P0'" type="info" effect="plain" content="P0"/>
|
||||
<ms-tag v-if="scope.row.level == 'P1'" type="warning" effect="plain" content="P1"/>
|
||||
<ms-tag v-if="scope.row.level == 'P2'" type="success" effect="plain" content="P2"/>
|
||||
<ms-tag v-if="scope.row.level == 'P3'" type="danger" effect="plain" content="P3"/>
|
||||
</template>
|
||||
<el-table ref="scenarioTable" border :data="tableData" class="adjust-table" @select-all="select" @select="select">
|
||||
<el-table-column type="selection"/>
|
||||
<el-table-column width="40" :resizable="false" align="center">
|
||||
<template v-slot:default="{row}">
|
||||
<show-more-btn :is-show="isSelect(row)" :buttons="buttons" :size="selection.length"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" :label="$t('api_test.automation.scenario_name')"
|
||||
show-overflow-tooltip/>
|
||||
<el-table-column prop="level" :label="$t('api_test.automation.case_level')"
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<ms-tag v-if="scope.row.level == 'P0'" type="info" effect="plain" content="P0"/>
|
||||
<ms-tag v-if="scope.row.level == 'P1'" type="warning" effect="plain" content="P1"/>
|
||||
<ms-tag v-if="scope.row.level == 'P2'" type="success" effect="plain" content="P2"/>
|
||||
<ms-tag v-if="scope.row.level == 'P3'" type="danger" effect="plain" content="P3"/>
|
||||
</template>
|
||||
|
||||
</el-table-column>
|
||||
<el-table-column prop="tagName" :label="$t('api_test.automation.tag')" show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<ms-tag type="success" effect="plain" v-if="scope.row.tagName!=undefined" :content="scope.row.tagName"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="userId" :label="$t('api_test.automation.creator')" show-overflow-tooltip/>
|
||||
<el-table-column prop="updateTime" :label="$t('api_test.automation.update_time')" width="180">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="stepTotal" :label="$t('api_test.automation.step')" show-overflow-tooltip/>
|
||||
<el-table-column prop="status" :label="$t('api_test.automation.last_result')">
|
||||
<template v-slot:default="{row}">
|
||||
<el-link type="success" v-if="row.status === 'Success'">{{ $t('api_test.automation.success') }}</el-link>
|
||||
<el-link type="danger" v-if="row.status === 'Fail'">{{ $t('api_test.automation.fail') }}</el-link>
|
||||
<el-link type="warning" v-if="row.status === 'Trash'">{{ $t('api_test.automation.trash') }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="passingRate" :label="$t('api_test.automation.passing_rate')"
|
||||
show-overflow-tooltip/>
|
||||
<el-table-column :label="$t('commons.operating')" width="180">
|
||||
<template v-slot:default="{row}">
|
||||
<el-button type="text" @click="edit(row)">{{ $t('api_test.automation.edit') }}</el-button>
|
||||
<el-button type="text" @click="execute(row)">{{ $t('api_test.automation.execute') }}</el-button>
|
||||
<el-button type="text" @click="copy(row)">{{ $t('api_test.automation.copy') }}</el-button>
|
||||
<el-button type="text" @click="remove(row)">{{ $t('api_test.automation.remove') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
|
||||
:total="total"/>
|
||||
</el-card>
|
||||
</el-table-column>
|
||||
<el-table-column prop="tagName" :label="$t('api_test.automation.tag')" show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<ms-tag type="success" effect="plain" v-if="scope.row.tagName!=undefined" :content="scope.row.tagName"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="userId" :label="$t('api_test.automation.creator')" show-overflow-tooltip/>
|
||||
<el-table-column prop="updateTime" :label="$t('api_test.automation.update_time')" width="180">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="stepTotal" :label="$t('api_test.automation.step')" show-overflow-tooltip/>
|
||||
<el-table-column prop="status" :label="$t('api_test.automation.last_result')">
|
||||
<template v-slot:default="{row}">
|
||||
<el-link type="success" v-if="row.status === 'Success'">{{ $t('api_test.automation.success') }}</el-link>
|
||||
<el-link type="danger" v-if="row.status === 'Fail'">{{ $t('api_test.automation.fail') }}</el-link>
|
||||
<el-link type="warning" v-if="row.status === 'Trash'">{{ $t('api_test.automation.trash') }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="passingRate" :label="$t('api_test.automation.passing_rate')"
|
||||
show-overflow-tooltip/>
|
||||
<el-table-column :label="$t('commons.operating')" width="180">
|
||||
<template v-slot:default="{row}">
|
||||
<el-button type="text" @click="edit(row)">{{ $t('api_test.automation.edit') }}</el-button>
|
||||
<el-button type="text" @click="execute(row)">{{ $t('api_test.automation.execute') }}</el-button>
|
||||
<el-button type="text" @click="copy(row)">{{ $t('api_test.automation.copy') }}</el-button>
|
||||
<el-button type="text" @click="remove(row)">{{ $t('api_test.automation.remove') }}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
|
||||
:total="total"/>
|
||||
|
||||
<div>
|
||||
<!-- 调试结果 -->
|
||||
<el-drawer :visible.sync="runVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
|
||||
<ms-api-report-detail :report-id="reportId" :currentProjectId="currentProject!=undefined ? currentProject.id:''"/>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -65,10 +75,11 @@
|
|||
import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn";
|
||||
import MsTag from "../../../common/components/MsTag";
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
import MsApiReportDetail from "../report/ApiReportDetail";
|
||||
|
||||
export default {
|
||||
name: "MsApiScenarioList",
|
||||
components: {ShowMoreBtn, MsTablePagination, MsTableHeader, MsTag},
|
||||
components: {ShowMoreBtn, MsTablePagination, MsTableHeader, MsTag, MsApiReportDetail},
|
||||
props: {
|
||||
currentProject: Object,
|
||||
currentModule: Object,
|
||||
|
@ -83,6 +94,9 @@
|
|||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
reportId: "",
|
||||
runVisible: false,
|
||||
runData: [],
|
||||
buttons: [
|
||||
{
|
||||
name: this.$t('api_test.automation.batch_add_plan'), handleClick: this.handleBatchAddCase
|
||||
|
@ -140,7 +154,16 @@
|
|||
|
||||
},
|
||||
handleBatchExecute() {
|
||||
|
||||
let url = "/api/automation/run";
|
||||
let run = {};
|
||||
let scenarioIds = this.selection;
|
||||
run.id = getUUID();
|
||||
run.scenarioIds = scenarioIds;
|
||||
this.result = this.$post(url, run, response => {
|
||||
let data = response.data;
|
||||
this.runVisible = true;
|
||||
this.reportId = run.id;
|
||||
});
|
||||
},
|
||||
selectAllChange() {
|
||||
this.handleCommand("table");
|
||||
|
@ -156,7 +179,17 @@
|
|||
this.$emit('edit', row);
|
||||
},
|
||||
execute(row) {
|
||||
|
||||
let url = "/api/automation/run";
|
||||
let run = {};
|
||||
let scenarioIds = [];
|
||||
scenarioIds.push(row.id);
|
||||
run.id = getUUID();
|
||||
run.scenarioIds = scenarioIds;
|
||||
this.result = this.$post(url, run, response => {
|
||||
let data = response.data;
|
||||
this.runVisible = true;
|
||||
this.reportId = run.id;
|
||||
});
|
||||
},
|
||||
copy(row) {
|
||||
row.id = getUUID();
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
<script>
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
import {createComponent} from "../../definition/components/jmeter/components";
|
||||
|
||||
export default {
|
||||
name: 'MsDebugRun',
|
||||
components: {},
|
||||
props: {
|
||||
environment: String,
|
||||
debug: Boolean,
|
||||
reportId: String,
|
||||
runData: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
loading: false,
|
||||
runId: "",
|
||||
reqNumber: 0,
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
// 初始化
|
||||
reportId() {
|
||||
this.run()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setFiles(item, bodyUploadFiles, obj) {
|
||||
if (item.body) {
|
||||
item.body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
if (!item.id) {
|
||||
let fileId = getUUID().substring(0, 12);
|
||||
item.name = item.file.name;
|
||||
item.id = fileId;
|
||||
}
|
||||
obj.bodyUploadIds.push(item.id);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
item.body.binary.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
if (!item.id) {
|
||||
let fileId = getUUID().substring(0, 12);
|
||||
item.name = item.file.name;
|
||||
item.id = fileId;
|
||||
}
|
||||
obj.bodyUploadIds.push(item.id);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
recursiveFile(arr, bodyUploadFiles, obj) {
|
||||
arr.forEach(item => {
|
||||
this.setFiles(item, bodyUploadFiles, obj);
|
||||
if (item.hashTree != undefined && item.hashTree.length > 0) {
|
||||
this.recursiveFile(item.hashTree, bodyUploadFiles, obj);
|
||||
}
|
||||
});
|
||||
},
|
||||
getBodyUploadFiles(obj) {
|
||||
let bodyUploadFiles = [];
|
||||
obj.bodyUploadIds = [];
|
||||
let request = this.runData;
|
||||
request.hashTree.forEach(item => {
|
||||
this.setFiles(item, bodyUploadFiles, obj);
|
||||
if (item.hashTree != undefined && item.hashTree.length > 0) {
|
||||
this.recursiveFile(item.hashTree, bodyUploadFiles, obj);
|
||||
}
|
||||
})
|
||||
return bodyUploadFiles;
|
||||
},
|
||||
run() {
|
||||
let testPlan = createComponent('TestPlan');
|
||||
let threadGroup = createComponent('ThreadGroup');
|
||||
threadGroup.hashTree = [];
|
||||
threadGroup.name = this.runData.name;
|
||||
threadGroup.hashTree.push(this.runData);
|
||||
testPlan.hashTree.push(threadGroup);
|
||||
let reqObj = {id: this.reportId, reportId: this.reportId, environmentId: this.environment, testElement: testPlan};
|
||||
let bodyFiles = this.getBodyUploadFiles(reqObj);
|
||||
console.log(bodyFiles)
|
||||
let url = "/api/automation/run/debug";
|
||||
this.$fileUpload(url, null, bodyFiles, reqObj, response => {
|
||||
this.runId = response.data;
|
||||
this.$emit('runRefresh', {});
|
||||
}, erro => {
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -261,7 +261,7 @@
|
|||
@runRefresh="runRefresh" ref="runTest"/>
|
||||
<!-- 调试结果 -->
|
||||
<el-drawer :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
|
||||
<ms-api-report-detail :report-id="reportId"/>
|
||||
<ms-api-report-detail :report-id="reportId" :currentProjectId="currentProject.id"/>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</el-card>
|
||||
|
@ -284,7 +284,7 @@
|
|||
import {getUUID} from "@/common/js/utils";
|
||||
import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig";
|
||||
import MsAddTag from "./AddTag";
|
||||
import MsRun from "./Run";
|
||||
import MsRun from "./DebugRun";
|
||||
import MsImportApiScenario from "./ImportApiScenario";
|
||||
import MsApiScenarioComponent from "./ApiScenarioComponent";
|
||||
import MsApiReportDetail from "../report/ApiReportDetail";
|
||||
|
@ -333,7 +333,7 @@
|
|||
expandedNode: [],
|
||||
scenarioDefinition: [],
|
||||
path: "/api/automation/create",
|
||||
debugData: [],
|
||||
debugData: {},
|
||||
reportId: "",
|
||||
}
|
||||
},
|
||||
|
@ -539,9 +539,7 @@
|
|||
this.$error(this.$t('api_test.environment.select_environment'));
|
||||
return;
|
||||
}
|
||||
let scenario = {id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition};
|
||||
this.debugData = [];
|
||||
this.debugData.push(scenario);
|
||||
this.debugData = {id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition};
|
||||
this.reportId = getUUID().substring(0, 8);
|
||||
},
|
||||
getEnvironments() {
|
||||
|
@ -592,11 +590,68 @@
|
|||
});
|
||||
return path[0].path;
|
||||
},
|
||||
setFiles(item, bodyUploadFiles, obj) {
|
||||
if (item.body) {
|
||||
item.body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
if (!item.id) {
|
||||
let fileId = getUUID().substring(0, 12);
|
||||
item.name = item.file.name;
|
||||
item.id = fileId;
|
||||
}
|
||||
obj.bodyUploadIds.push(item.id);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
item.body.binary.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
if (!item.id) {
|
||||
let fileId = getUUID().substring(0, 12);
|
||||
item.name = item.file.name;
|
||||
item.id = fileId;
|
||||
}
|
||||
obj.bodyUploadIds.push(item.id);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
recursiveFile(arr, bodyUploadFiles, obj) {
|
||||
arr.forEach(item => {
|
||||
this.setFiles(item, bodyUploadFiles, obj);
|
||||
if (item.hashTree != undefined && item.hashTree.length > 0) {
|
||||
this.recursiveFile(item.hashTree, bodyUploadFiles, obj);
|
||||
}
|
||||
});
|
||||
},
|
||||
getBodyUploadFiles(obj) {
|
||||
let bodyUploadFiles = [];
|
||||
obj.bodyUploadIds = [];
|
||||
this.scenarioDefinition.forEach(item => {
|
||||
this.setFiles(item, bodyUploadFiles, obj);
|
||||
if (item.hashTree != undefined && item.hashTree.length > 0) {
|
||||
this.recursiveFile(item.hashTree, bodyUploadFiles, obj);
|
||||
}
|
||||
})
|
||||
return bodyUploadFiles;
|
||||
},
|
||||
editScenario() {
|
||||
this.$refs['currentScenario'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.setParameter();
|
||||
this.result = this.$post(this.path, this.currentScenario, () => {
|
||||
let bodyFiles = this.getBodyUploadFiles(this.currentScenario);
|
||||
console.log(bodyFiles)
|
||||
console.log(this.currentScenario.bodyUploadIds)
|
||||
|
||||
this.$fileUpload(this.path, null, bodyFiles, this.currentScenario, () => {
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.path = "/api/automation/update";
|
||||
this.currentScenario.tagId = JSON.parse(this.currentScenario.tagId);
|
||||
|
|
|
@ -1,118 +0,0 @@
|
|||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
<script>
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
import ThreadGroup from "../../definition/components/jmeter/components/thread-group";
|
||||
import TestPlan from "../../definition/components/jmeter/components/test-plan";
|
||||
|
||||
export default {
|
||||
name: 'MsRun',
|
||||
components: {},
|
||||
props: {
|
||||
environment: String,
|
||||
debug: Boolean,
|
||||
reportId: String,
|
||||
runData: Array,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
loading: false,
|
||||
runId: "",
|
||||
reqNumber: 0,
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
// 初始化
|
||||
reportId() {
|
||||
this.run()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getResult() {
|
||||
if (this.runId) {
|
||||
let url = "";
|
||||
if (this.debug) {
|
||||
url = "/api/definition/report/get/" + this.runId + "/" + "debug";
|
||||
} else {
|
||||
url = "/api/definition/report/get/" + this.runId + "/" + "run";
|
||||
}
|
||||
this.$get(url, response => {
|
||||
if (response.data) {
|
||||
let data = JSON.parse(response.data.content);
|
||||
this.$emit('runRefresh', data);
|
||||
} else {
|
||||
if (this.reqNumber < 60) {
|
||||
this.reqNumber++;
|
||||
setTimeout(this.getResult, 2000);
|
||||
} else {
|
||||
this.$error("获取报告超时");
|
||||
this.$emit('runRefresh', {});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
getBodyUploadFiles(obj) {
|
||||
let bodyUploadFiles = [];
|
||||
obj.bodyUploadIds = [];
|
||||
this.runData.forEach(request => {
|
||||
if (request.body) {
|
||||
request.body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
if (!item.id) {
|
||||
let fileId = getUUID().substring(0, 12);
|
||||
item.name = item.file.name;
|
||||
item.id = fileId;
|
||||
}
|
||||
obj.bodyUploadIds.push(item.id);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
request.body.binary.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
if (!item.id) {
|
||||
let fileId = getUUID().substring(0, 12);
|
||||
item.name = item.file.name;
|
||||
item.id = fileId;
|
||||
}
|
||||
obj.bodyUploadIds.push(item.id);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return bodyUploadFiles;
|
||||
},
|
||||
run() {
|
||||
let testPlan = new TestPlan();
|
||||
this.runData.forEach(item => {
|
||||
let threadGroup = new ThreadGroup();
|
||||
threadGroup.hashTree = [];
|
||||
threadGroup.name = item.name;
|
||||
threadGroup.hashTree.push(item);
|
||||
testPlan.hashTree.push(threadGroup);
|
||||
})
|
||||
console.log("====",testPlan)
|
||||
let reqObj = {id: this.reportId, reportId: this.reportId, environmentId: this.environment, testElement: testPlan};
|
||||
let bodyFiles = this.getBodyUploadFiles(reqObj);
|
||||
let url = "/api/automation/run";
|
||||
this.$fileUpload(url, null, bodyFiles, reqObj, response => {
|
||||
this.runId = response.data;
|
||||
this.$emit('runRefresh', {});
|
||||
}, erro => {
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -12,12 +12,7 @@ export const TYPE = "TestPlan";
|
|||
export default class TestPlan extends HashTreeElement {
|
||||
constructor(options = DEFAULT_OPTIONS) {
|
||||
super(options);
|
||||
this.$type = TYPE;
|
||||
this.type = TYPE;
|
||||
this.functionalMode = this.initBoolProp('TestPlan.functional_mode', false);
|
||||
this.serializeThreadGroups = this.initBoolProp('TestPlan.serialize_threadgroups', false);
|
||||
this.tearDownOnShutdown = this.initBoolProp('TestPlan.tearDown_on_shutdown', true);
|
||||
this.userDefineClasspath = this.initStringProp('TestPlan.user_define_classpath');
|
||||
this.hashTree = [];
|
||||
this.userDefinedVariables = [];
|
||||
|
||||
|
|
|
@ -11,21 +11,7 @@ export const TYPE = "ThreadGroup";
|
|||
export default class ThreadGroup extends HashTreeElement {
|
||||
constructor(options = DEFAULT_OPTIONS) {
|
||||
super(options);
|
||||
this.$type = TYPE;
|
||||
this.type = TYPE;
|
||||
this.onSampleError = this.initStringProp('ThreadGroup.on_sample_error', 'continue');
|
||||
this.numThreads = this.initStringProp('ThreadGroup.num_threads', 1);
|
||||
this.rampTime = this.initStringProp('ThreadGroup.ramp_time', 1);
|
||||
|
||||
let loopController = this.initElementProp('ThreadGroup.main_controller', 'LoopController');
|
||||
this.continueForever = loopController.initBoolProp('LoopController.continue_forever', false);
|
||||
this.loops = loopController.initStringProp('LoopController.loops', 1);
|
||||
|
||||
this.sameUserOnNextIteration = this.initBoolProp('ThreadGroup.same_user_on_next_iteration', true);
|
||||
this.delayedStart = this.initBoolProp('ThreadGroup.delayedStart');
|
||||
this.scheduler = this.initBoolProp('ThreadGroup.scheduler', false);
|
||||
this.delay = this.initStringProp('ThreadGroup.delay');
|
||||
this.duration = this.initStringProp('ThreadGroup.duration');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,18 @@
|
|||
<el-row type="flex">
|
||||
<el-col :span="10">
|
||||
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router :default-active='$route.path'>
|
||||
|
||||
<el-submenu :class="{'deactivation':!isProjectActivation}" v-permission="['test_manager','test_user','test_viewer']" index="3">
|
||||
<template v-slot:title>{{ $t('commons.project') }}</template>
|
||||
<search-list ref="projectRecent" :options="projectRecent"/>
|
||||
<el-divider class="menu-divider"/>
|
||||
<el-menu-item :index="'/performance/project/create'">
|
||||
<font-awesome-icon :icon="['fa', 'plus']"/>
|
||||
<span style="padding-left: 7px;">创建项目</span>
|
||||
</el-menu-item>
|
||||
<ms-show-all :index="'/setting/project'"/>
|
||||
</el-submenu>
|
||||
|
||||
<el-menu-item :index="'/api/home'">
|
||||
{{ $t("i18n.home") }}
|
||||
</el-menu-item>
|
||||
|
@ -15,14 +27,9 @@
|
|||
{{ $t("i18n.automation") }}
|
||||
</el-menu-item>
|
||||
|
||||
<el-submenu :class="{'deactivation':!isProjectActivation}" v-permission="['test_manager','test_user','test_viewer']" index="3">
|
||||
<template v-slot:title>{{ $t('commons.project') }}</template>
|
||||
<ms-recent-list ref="projectRecent" :options="projectRecent"/>
|
||||
<el-divider class="menu-divider"/>
|
||||
<ms-show-all :index="'/api/project/all'"/>
|
||||
<ms-create-button v-permission="['test_manager','test_user']" :index="'/api/project/create'"
|
||||
:title="$t('project.create')"/>
|
||||
</el-submenu>
|
||||
<el-menu-item :index="'/api/automation/report'">
|
||||
{{ $t("i18n.report") }}
|
||||
</el-menu-item>
|
||||
|
||||
<el-submenu v-permission="['test_manager','test_user','test_viewer']" index="4">
|
||||
<template v-slot:title>{{ $t('commons.test') }}</template>
|
||||
|
@ -65,10 +72,11 @@ import MsShowAll from "../../common/head/ShowAll";
|
|||
import MsCreateButton from "../../common/head/CreateButton";
|
||||
import MsCreateTest from "../../common/head/CreateTest";
|
||||
import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent";
|
||||
import SearchList from "@/business/components/common/head/SearchList";
|
||||
|
||||
export default {
|
||||
name: "MsApiHeaderMenus",
|
||||
components: {MsCreateTest, MsCreateButton, MsShowAll, MsRecentList},
|
||||
components: {SearchList, MsCreateTest, MsCreateButton, MsShowAll, MsRecentList},
|
||||
data() {
|
||||
return {
|
||||
projectRecent: {
|
||||
|
|
|
@ -48,6 +48,11 @@ export default {
|
|||
path: "automation",
|
||||
name: "ApiAutomation",
|
||||
component: () => import('@/business/components/api/automation/ApiAutomation'),
|
||||
},
|
||||
{
|
||||
path: "automation/report",
|
||||
name: "ApiReportList",
|
||||
component: () => import('@/business/components/api/automation/report/ApiReportList'),
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
|
||||
<div>
|
||||
<el-row class="table-title" type="flex" justify="space-between" align="middle">
|
||||
<el-row v-if="title" class="table-title" type="flex" justify="space-between" align="middle">
|
||||
<slot name="title">
|
||||
{{title}}
|
||||
</slot>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<span>
|
||||
<el-submenu index="10">
|
||||
<template v-slot:title>操作</template>
|
||||
<el-input
|
||||
placeholder="请输入内容"
|
||||
prefix-icon="el-icon-search"
|
||||
v-model="input2">
|
||||
</el-input>
|
||||
</el-submenu>
|
||||
</span>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ProjectMenu",
|
||||
data() {
|
||||
return {
|
||||
input2: '1'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,107 @@
|
|||
<template>
|
||||
<div v-loading="result.loading" class="search-list">
|
||||
<el-input placeholder="搜索项目"
|
||||
prefix-icon="el-icon-search"
|
||||
v-model="search_text"
|
||||
clearable
|
||||
class="search-input"
|
||||
size="small"/>
|
||||
<div v-if="items.length === 0" style="text-align: center; margin: 15px 0">
|
||||
<span style="font-size: 15px; color: #8a8b8d;">
|
||||
无数据
|
||||
</span>
|
||||
</div>
|
||||
<div v-else style="height: 120px;overflow: auto">
|
||||
<el-menu-item :key="i.id" v-for="i in items" :index="getIndex(i)" :route="getRouter(i)">
|
||||
<template slot="title">
|
||||
<div class="title">{{ i.name }}</div>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {hasRoles} from "@/common/js/utils";
|
||||
import {ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "@/common/js/constants";
|
||||
|
||||
export default {
|
||||
name: "SearchList",
|
||||
props: {
|
||||
options: Object
|
||||
},
|
||||
mounted() {
|
||||
this.recent();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
items: [],
|
||||
search_text: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
search_text(val) {
|
||||
if (!val) {
|
||||
this.recent();
|
||||
} else {
|
||||
this.search();
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getIndex: function () {
|
||||
return function (item) {
|
||||
return this.options.index(item);
|
||||
}
|
||||
},
|
||||
getRouter: function () {
|
||||
return function (item) {
|
||||
if (this.options.router) {
|
||||
return this.options.router(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
recent: function () {
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.result = this.$get(this.options.url, (response) => {
|
||||
this.items = response.data;
|
||||
this.items = this.items.splice(0, 3);
|
||||
});
|
||||
}
|
||||
},
|
||||
search() {
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.result = this.$post("/project/search", {name: this.search_text},response => {
|
||||
this.items = response.data;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.search-input {
|
||||
padding: 0;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
.search-input >>> .el-input__inner {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: inline-block;
|
||||
padding-left: 20px;
|
||||
max-width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<el-menu-item :index="this.index" @click="changeRoute">
|
||||
<el-menu-item :index="this.index">
|
||||
<font-awesome-icon :icon="['fa', 'list-ul']"/>
|
||||
<span>{{ $t('commons.show_all') }}</span>
|
||||
</el-menu-item>
|
||||
|
@ -10,14 +10,6 @@ export default {
|
|||
name: "MsShowAll",
|
||||
props: {
|
||||
index: String
|
||||
},
|
||||
methods: {
|
||||
changeRoute() {
|
||||
// 解决在列表页面点击 显示全部 无效的问题(点击显示全部后改变路由)
|
||||
if (this.$route.path === this.index) {
|
||||
this.$router.replace({path: this.index, query: {type: 'all'}});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -3,20 +3,23 @@
|
|||
<el-row type="flex">
|
||||
<el-col :span="8">
|
||||
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router :default-active='$route.path'>
|
||||
<el-menu-item :index="'/performance/home'">
|
||||
{{ $t("i18n.home") }}
|
||||
</el-menu-item>
|
||||
|
||||
<el-submenu v-permission="['test_manager','test_user','test_viewer']"
|
||||
index="3" popper-class="submenu">
|
||||
<template v-slot:title>{{ $t('commons.project') }}</template>
|
||||
<ms-recent-list ref="projectRecent" :options="projectRecent"/>
|
||||
<search-list ref="projectRecent" :options="projectRecent"/>
|
||||
<el-divider/>
|
||||
<ms-show-all :index="'/performance/project/all'"/>
|
||||
<ms-create-button v-permission="['test_manager','test_user']" :index="'/performance/project/create'"
|
||||
:title="$t('project.create')"/>
|
||||
<el-menu-item :index="'/performance/project/create'">
|
||||
<font-awesome-icon :icon="['fa', 'plus']"/>
|
||||
<span style="padding-left: 7px;">创建项目</span>
|
||||
</el-menu-item>
|
||||
<ms-show-all :index="'/setting/project'"/>
|
||||
</el-submenu>
|
||||
|
||||
<el-menu-item :index="'/performance/home'">
|
||||
{{ $t("i18n.home") }}
|
||||
</el-menu-item>
|
||||
|
||||
<el-submenu v-permission="['test_manager','test_user','test_viewer']"
|
||||
index="4" popper-class="submenu">
|
||||
<template v-slot:title>{{ $t('commons.test') }}</template>
|
||||
|
@ -53,10 +56,12 @@ import MsRecentList from "../../common/head/RecentList";
|
|||
import MsCreateButton from "../../common/head/CreateButton";
|
||||
import MsShowAll from "../../common/head/ShowAll";
|
||||
import {LIST_CHANGE, PerformanceEvent} from "@/business/components/common/head/ListEvent";
|
||||
import SearchList from "@/business/components/common/head/SearchList";
|
||||
|
||||
export default {
|
||||
name: "PerformanceHeaderMenus",
|
||||
components: {
|
||||
SearchList,
|
||||
MsCreateButton,
|
||||
MsShowAll,
|
||||
MsRecentList,
|
||||
|
@ -92,7 +97,8 @@ export default {
|
|||
},
|
||||
router(item) {
|
||||
}
|
||||
}
|
||||
},
|
||||
input2: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<el-card class="table-card" v-loading="result.loading">
|
||||
<template v-slot:header>
|
||||
<ms-table-header :is-tester-permission="true" :condition.sync="condition" @search="search" @create="create"
|
||||
:create-tip="btnTips" :title="title"/>
|
||||
:create-tip="btnTips" title=""/>
|
||||
</template>
|
||||
<el-table border class="adjust-table" @row-click="link" :data="items" style="width: 100%" @sort-change="sort">
|
||||
<el-table-column prop="name" :label="$t('commons.name')" width="250" show-overflow-tooltip/>
|
||||
|
@ -36,7 +36,7 @@
|
|||
<template v-slot:default="scope">
|
||||
<ms-table-operator :is-tester-permission="true" @editClick="edit(scope.row)"
|
||||
@deleteClick="handleDelete(scope.row)">
|
||||
<template v-if="baseUrl == 'api'" v-slot:behind>
|
||||
<template v-slot:behind>
|
||||
<ms-table-operator-button :is-tester-permission="true" :tip="$t('api_test.environment.environment_config')" icon="el-icon-setting"
|
||||
type="info" @exec="openEnvironmentConfig(scope.row)"/>
|
||||
</template>
|
||||
|
@ -188,21 +188,19 @@ export default {
|
|||
this.createVisible = true;
|
||||
listenGoBack(this.handleClose);
|
||||
this.form = Object.assign({}, row);
|
||||
if (this.baseUrl === 'track') {
|
||||
this.$get("/service/integration/all/" + getCurrentUser().lastOrganizationId, response => {
|
||||
let data = response.data;
|
||||
let platforms = data.map(d => d.platform);
|
||||
if (platforms.indexOf("Tapd") !== -1) {
|
||||
this.tapd = true;
|
||||
}
|
||||
if (platforms.indexOf("Jira") !== -1) {
|
||||
this.jira = true;
|
||||
}
|
||||
if (platforms.indexOf("Zentao") !== -1) {
|
||||
this.zentao = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
this.$get("/service/integration/all/" + getCurrentUser().lastOrganizationId, response => {
|
||||
let data = response.data;
|
||||
let platforms = data.map(d => d.platform);
|
||||
if (platforms.indexOf("Tapd") !== -1) {
|
||||
this.tapd = true;
|
||||
}
|
||||
if (platforms.indexOf("Jira") !== -1) {
|
||||
this.jira = true;
|
||||
}
|
||||
if (platforms.indexOf("Zentao") !== -1) {
|
||||
this.zentao = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
submit(formName) {
|
||||
|
|
|
@ -41,6 +41,14 @@
|
|||
</el-menu-item>
|
||||
</el-submenu>
|
||||
|
||||
<el-menu-item v-for="menu in project" :key="menu.index" :index="menu.index" class="setting-item"
|
||||
v-permission="menu.roles">
|
||||
<template v-slot:title>
|
||||
<font-awesome-icon class="icon" :icon="['fa', 'bars']" size="lg"/>
|
||||
<span>{{ $t(menu.title) }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
|
@ -73,6 +81,7 @@
|
|||
organizations: getMenus('organization'),
|
||||
workspaces: getMenus('workspace'),
|
||||
persons: getMenus('person'),
|
||||
project: getMenus('project'),
|
||||
isCurrentOrganizationAdmin: false,
|
||||
isCurrentWorkspaceUser: false,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<template>
|
||||
<el-card>
|
||||
<el-tabs class="system-setting" v-model="activeName">
|
||||
<el-tab-pane label="项目管理" name="project">
|
||||
<ms-project/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsProject from "@/business/components/project/MsProject";
|
||||
export default {
|
||||
name: "Project",
|
||||
components: {MsProject},
|
||||
data() {
|
||||
return {
|
||||
activeName: 'project'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -79,6 +79,11 @@ export default {
|
|||
roles: ['test_manager', 'test_user', 'test_viewer', 'org_admin', 'admin']
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'project',
|
||||
component: () => import('@/business/components/settings/project/Project'),
|
||||
meta: {project: true, title: '项目管理'}
|
||||
},
|
||||
|
||||
]
|
||||
}
|
||||
|
|
|
@ -5,19 +5,22 @@
|
|||
<el-col :span="12">
|
||||
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router
|
||||
:default-active='$route.path'>
|
||||
<el-menu-item :index="'/track/home'">
|
||||
{{ $t("i18n.home") }}
|
||||
</el-menu-item>
|
||||
<el-submenu :class="{'deactivation':!isProjectActivation}"
|
||||
v-permission="['test_manager','test_user','test_viewer']" index="3" popper-class="submenu">
|
||||
<template v-slot:title>{{ $t('commons.project') }}</template>
|
||||
<ms-recent-list ref="projectRecent" :options="projectRecent"/>
|
||||
<search-list ref="projectRecent" :options="projectRecent"/>
|
||||
<el-divider/>
|
||||
<ms-show-all :index="'/track/project/all'"/>
|
||||
<ms-create-button v-permission="['test_manager','test_user']" :index="'/track/project/create'"
|
||||
:title="$t('project.create')"/>
|
||||
<el-menu-item :index="'/performance/project/create'">
|
||||
<font-awesome-icon :icon="['fa', 'plus']"/>
|
||||
<span style="padding-left: 7px;">创建项目</span>
|
||||
</el-menu-item>
|
||||
<ms-show-all :index="'/setting/project'"/>
|
||||
</el-submenu>
|
||||
|
||||
<el-menu-item :index="'/track/home'">
|
||||
{{ $t("i18n.home") }}
|
||||
</el-menu-item>
|
||||
|
||||
<el-submenu v-permission="['test_manager','test_user','test_viewer']"
|
||||
index="6" popper-class="submenu">
|
||||
<template v-slot:title>{{ $t('test_track.case.test_case') }}</template>
|
||||
|
@ -62,10 +65,11 @@ import MsShowAll from "../../common/head/ShowAll";
|
|||
import MsRecentList from "../../common/head/RecentList";
|
||||
import MsCreateButton from "../../common/head/CreateButton";
|
||||
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
||||
import SearchList from "@/business/components/common/head/SearchList";
|
||||
|
||||
export default {
|
||||
name: "TrackHeaderMenus",
|
||||
components: {MsShowAll, MsRecentList, MsCreateButton},
|
||||
components: {SearchList, MsShowAll, MsRecentList, MsCreateButton},
|
||||
data() {
|
||||
return {
|
||||
testPlanViewPath: '',
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit a22a3005d9bd254793fcf634d72539cbdf31be3a
|
||||
Subproject commit 8a972a198775b3783ed6e4cef27197e53d1ebdc8
|
|
@ -28,7 +28,7 @@ export const xpack = {
|
|||
function checkLicense(el, binding, type) {
|
||||
let v = hasLicense()
|
||||
|
||||
if (v) {
|
||||
if (!v) {
|
||||
el.parentNode && el.parentNode.removeChild(el)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ export default {
|
|||
current_user: "Current user"
|
||||
}
|
||||
},
|
||||
monitor:"monitor"
|
||||
monitor: "monitor"
|
||||
},
|
||||
license: {
|
||||
title: 'Authorization management',
|
||||
|
@ -543,6 +543,7 @@ export default {
|
|||
customize_script: "Custom script",
|
||||
customize_req: "Custom request",
|
||||
reference_info: "Please select interface or use case",
|
||||
report_name_info: 'Please enter the registration name',
|
||||
},
|
||||
environment: {
|
||||
name: "Environment Name",
|
||||
|
@ -779,14 +780,14 @@ export default {
|
|||
not_exist: "Test report does not exist",
|
||||
},
|
||||
api_monitor: {
|
||||
to:"to",
|
||||
start_time:"Start Time",
|
||||
end_time:"End Time",
|
||||
today:"Today",
|
||||
this_week:"This Week",
|
||||
this_mouth:"This Mouth",
|
||||
please_search:"Please Search",
|
||||
date:"Date"
|
||||
to: "to",
|
||||
start_time: "Start Time",
|
||||
end_time: "End Time",
|
||||
today: "Today",
|
||||
this_week: "This Week",
|
||||
this_mouth: "This Mouth",
|
||||
please_search: "Please Search",
|
||||
date: "Date"
|
||||
},
|
||||
test_track: {
|
||||
test_track: "Track",
|
||||
|
@ -1096,6 +1097,7 @@ export default {
|
|||
home: 'Home',
|
||||
definition: 'Api Definition',
|
||||
automation: 'Api Automation',
|
||||
report: 'Test report',
|
||||
},
|
||||
ldap: {
|
||||
url: 'LDAP URL',
|
||||
|
|
|
@ -570,7 +570,8 @@ export default {
|
|||
follow_people: "关注人",
|
||||
select_table: "选择可见数据",
|
||||
select_all: "选择全部数据"
|
||||
}
|
||||
},
|
||||
report_name_info: '请输入报名名称',
|
||||
},
|
||||
environment: {
|
||||
name: "环境名称",
|
||||
|
@ -809,14 +810,14 @@ export default {
|
|||
not_exist: "测试报告不存在",
|
||||
},
|
||||
api_monitor: {
|
||||
to:"至",
|
||||
start_time:"开始日期",
|
||||
end_time:"结束日期",
|
||||
today:"今日",
|
||||
this_week:"本周",
|
||||
this_mouth:"本月",
|
||||
please_search:"请搜索",
|
||||
date:"日期"
|
||||
to: "至",
|
||||
start_time: "开始日期",
|
||||
end_time: "结束日期",
|
||||
today: "今日",
|
||||
this_week: "本周",
|
||||
this_mouth: "本月",
|
||||
please_search: "请搜索",
|
||||
date: "日期"
|
||||
},
|
||||
test_track: {
|
||||
test_track: "测试跟踪",
|
||||
|
@ -1125,6 +1126,7 @@ export default {
|
|||
home: '首页',
|
||||
definition: '接口定义',
|
||||
automation: '接口自动化',
|
||||
report: '测试报告',
|
||||
},
|
||||
ldap: {
|
||||
url: 'LDAP地址',
|
||||
|
|
|
@ -543,8 +543,8 @@ export default {
|
|||
scenario_import: "場景導入",
|
||||
customize_script: "自定義腳本",
|
||||
customize_req: "自定義請求",
|
||||
reference_info: "請選擇接口或用例"
|
||||
|
||||
reference_info: "請選擇接口或用例",
|
||||
report_name_info: '请输入报名名称',
|
||||
},
|
||||
environment: {
|
||||
name: "環境名稱",
|
||||
|
@ -1098,6 +1098,7 @@ export default {
|
|||
home: '首頁',
|
||||
definition: '接口定義',
|
||||
automation: '接口自動化',
|
||||
report: '測試報告',
|
||||
},
|
||||
ldap: {
|
||||
url: 'LDAP地址',
|
||||
|
|
Loading…
Reference in New Issue