This commit is contained in:
chenjianxing 2020-12-07 20:17:32 +08:00
commit 0d8d12b17b
48 changed files with 1410 additions and 425 deletions

View File

@ -1,16 +1,22 @@
package io.metersphere.api.controller; 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.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.api.service.ApiScenarioReportService;
import io.metersphere.commons.constants.RoleConstants; 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.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List;
@RestController @RestController
@RequestMapping(value = "/api/scenario/report") @RequestMapping(value = "/api/scenario/report")
@ -20,8 +26,41 @@ public class APIScenarioReportController {
@Resource @Resource
private ApiScenarioReportService apiReportService; private ApiScenarioReportService apiReportService;
@GetMapping("/get/{reportId}") @GetMapping("/get/{reportId}/{infoDb}")
public APIReportResult get(@PathVariable String reportId) { public APIReportResult get(@PathVariable String reportId,@PathVariable Boolean infoDb) {
if(infoDb){
return apiReportService.get(reportId);
}
return apiReportService.getCacheResult(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);
}
} }

View File

@ -4,6 +4,7 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.metersphere.api.dto.automation.ApiScenarioDTO; import io.metersphere.api.dto.automation.ApiScenarioDTO;
import io.metersphere.api.dto.automation.ApiScenarioRequest; 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.automation.SaveApiScenarioRequest;
import io.metersphere.api.dto.definition.RunDefinitionRequest; import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.service.ApiAutomationService; import io.metersphere.api.service.ApiAutomationService;
@ -36,13 +37,13 @@ public class ApiAutomationController {
} }
@PostMapping(value = "/create") @PostMapping(value = "/create")
public void create(@RequestBody SaveApiScenarioRequest request) { public void create(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiAutomationService.create(request); apiAutomationService.create(request, bodyFiles);
} }
@PostMapping(value = "/update") @PostMapping(value = "/update")
public void update(@RequestBody SaveApiScenarioRequest request) { public void update(@RequestPart("request") SaveApiScenarioRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiAutomationService.update(request); apiAutomationService.update(request, bodyFiles);
} }
@GetMapping("/delete/{id}") @GetMapping("/delete/{id}")
@ -70,9 +71,15 @@ public class ApiAutomationController {
return apiAutomationService.getApiScenarios(ids); return apiAutomationService.getApiScenarios(ids);
} }
@PostMapping(value = "/run") @PostMapping(value = "/run/debug")
public void runDebug(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) { public void runDebug(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
apiAutomationService.run(request, bodyFiles); apiAutomationService.run(request, bodyFiles);
} }
@PostMapping(value = "/run")
public void run(@RequestBody RunScenarioRequest request) {
apiAutomationService.run(request);
}
} }

View File

@ -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;
}

View File

@ -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;
}

View File

@ -3,6 +3,8 @@ package io.metersphere.api.dto.automation;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.List;
@Setter @Setter
@Getter @Getter
public class SaveApiScenarioRequest { public class SaveApiScenarioRequest {
@ -35,4 +37,6 @@ public class SaveApiScenarioRequest {
private String description; private String description;
private String scenarioDefinition; private String scenarioDefinition;
List<String> bodyUploadIds;
} }

View File

@ -4,6 +4,9 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField; import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType; 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.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.service.ApiAutomationService; import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.api.service.ApiTestEnvironmentService; import io.metersphere.api.service.ApiTestEnvironmentService;
@ -15,6 +18,7 @@ import lombok.EqualsAndHashCode;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import java.util.LinkedList;
import java.util.List; import java.util.List;
@Data @Data
@ -41,14 +45,21 @@ public class MsScenario extends MsTestElement {
if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) { if (this.getReferenced() != null && this.getReferenced().equals("Deleted")) {
return; return;
} else if (this.getReferenced() != null && this.getReferenced().equals("REF")) { } else if (this.getReferenced() != null && this.getReferenced().equals("REF")) {
try {
ApiAutomationService apiAutomationService = CommonBeanFactory.getBean(ApiAutomationService.class); ApiAutomationService apiAutomationService = CommonBeanFactory.getBean(ApiAutomationService.class);
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ApiScenario scenario = apiAutomationService.getApiScenario(this.getId()); ApiScenario scenario = apiAutomationService.getApiScenario(this.getId());
JSONObject element = JSON.parseObject(scenario.getScenarioDefinition()); JSONObject element = JSON.parseObject(scenario.getScenarioDefinition());
List<MsTestElement> dataArr = JSON.parseArray(element.getString("hashTree"), MsTestElement.class); LinkedList<MsTestElement> elements = mapper.readValue(element.getString("hashTree"), new TypeReference<LinkedList<MsTestElement>>() {
});
if (hashTree == null) { if (hashTree == null) {
hashTree = dataArr; hashTree = elements;
} else { } else {
hashTree.addAll(dataArr); hashTree.addAll(elements);
}
} catch (Exception ex) {
ex.printStackTrace();
} }
} }
if (CollectionUtils.isNotEmpty(hashTree)) { if (CollectionUtils.isNotEmpty(hashTree)) {

View File

@ -51,7 +51,7 @@ import java.util.List;
MsJSR223PreProcessor.class, MsTestPlan.class, MsThreadGroup.class, AuthManager.class, MsAssertions.class, 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") MsExtract.class, MsTCPSampler.class, MsDubboSampler.class, MsJDBCSampler.class, MsConstantTimer.class, MsIfController.class, MsScenario.class}, typeKey = "type")
@Data @Data
public abstract class MsTestElement { public class MsTestElement {
private String type; private String type;
@JSONField(ordinal = 1) @JSONField(ordinal = 1)
private String id; private String id;

View File

@ -50,4 +50,5 @@ public class MsThreadGroup extends MsTestElement {
threadGroup.setSamplerController(loopController); threadGroup.setSamplerController(loopController);
return threadGroup; return threadGroup;
} }
} }

View File

@ -169,7 +169,7 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
} }
} else if (StringUtils.equals(this.runMode, ApiRunMode.SCENARIO.name())) { } else if (StringUtils.equals(this.runMode, ApiRunMode.SCENARIO.name())) {
// 执行报告不需要存储由用户确认后在存储 // 执行报告不需要存储由用户确认后在存储
testResult.setTestId(debugReportId); testResult.setTestId(testId);
apiScenarioReportService.complete(testResult); apiScenarioReportService.complete(testResult);
} else { } else {
apiTestService.changeStatus(testId, APITestStatus.Completed); apiTestService.changeStatus(testId, APITestStatus.Completed);

View File

@ -2,13 +2,16 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; 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 com.google.gson.Gson;
import io.metersphere.api.dto.APIReportResult; import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.automation.ApiScenarioDTO; import io.metersphere.api.dto.automation.*;
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.definition.RunDefinitionRequest; 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.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.api.jmeter.JMeterService; import io.metersphere.api.jmeter.JMeterService;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
@ -24,6 +27,7 @@ import io.metersphere.i18n.Translator;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.jorphan.collections.HashTree; import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import org.aspectj.util.FileUtil; import org.aspectj.util.FileUtil;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -32,9 +36,9 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.io.*; import java.io.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@ -83,8 +87,9 @@ public class ApiAutomationService {
apiScenarioMapper.deleteByExample(example); apiScenarioMapper.deleteByExample(example);
} }
public void create(SaveApiScenarioRequest request) { public void create(SaveApiScenarioRequest request, List<MultipartFile> bodyFiles) {
checkNameExist(request); checkNameExist(request);
final ApiScenario scenario = new ApiScenario(); final ApiScenario scenario = new ApiScenario();
scenario.setId(request.getId()); scenario.setId(request.getId());
scenario.setName(request.getName()); scenario.setName(request.getName());
@ -111,10 +116,16 @@ public class ApiAutomationService {
} }
scenario.setDescription(request.getDescription()); scenario.setDescription(request.getDescription());
apiScenarioMapper.insert(scenario); 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); checkNameExist(request);
List<String> bodyUploadIds = new ArrayList<>(request.getBodyUploadIds());
createBodyFiles(bodyUploadIds, bodyFiles);
final ApiScenario scenario = new ApiScenario(); final ApiScenario scenario = new ApiScenario();
scenario.setId(request.getId()); scenario.setId(request.getId());
scenario.setName(request.getName()); scenario.setName(request.getName());
@ -176,7 +187,7 @@ public class ApiAutomationService {
} }
private void createBodyFiles(List<String> bodyUploadIds, List<MultipartFile> bodyFiles) { private void createBodyFiles(List<String> bodyUploadIds, List<MultipartFile> bodyFiles) {
if (!bodyUploadIds.isEmpty()) { if (!bodyUploadIds.isEmpty() && !bodyFiles.isEmpty()) {
File testDir = new File(BODY_FILE_DIR); File testDir = new File(BODY_FILE_DIR);
if (!testDir.exists()) { if (!testDir.exists()) {
testDir.mkdirs(); 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()); jMeterService.runDefinition(request.getId(), hashTree, request.getReportId(), ApiRunMode.SCENARIO.name());
APIReportResult report = new APIReportResult(); createAPIReportResult(request.getId());
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);
return request.getId(); return request.getId();
} }
} }

View File

@ -2,23 +2,39 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.APIReportResult; 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.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.constants.APITestStatus;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import sun.security.util.Cache; import sun.security.util.Cache;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.UUID;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public class ApiScenarioReportService { public class ApiScenarioReportService {
private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24); 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) { public void complete(TestResult result) {
Object obj = cache.get(result.getTestId()); Object obj = cache.get(result.getTestId());
@ -64,4 +80,103 @@ public class ApiScenarioReportService {
} }
return null; 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);
}
} }

View File

@ -1,13 +1,14 @@
package io.metersphere.base.domain; package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data; import lombok.Data;
import java.io.Serializable;
@Data @Data
public class ApiScenarioReport implements Serializable { public class ApiScenarioReport implements Serializable {
private String id; private String id;
private String scenarioId; private String projectId;
private String name; private String name;

View File

@ -7,7 +7,7 @@ import lombok.Data;
public class ApiScenarioReportDetail implements Serializable { public class ApiScenarioReportDetail implements Serializable {
private String reportId; private String reportId;
private String scenarioId; private String projectId;
private byte[] content; private byte[] content;

View File

@ -174,73 +174,73 @@ public class ApiScenarioReportDetailExample {
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIsNull() { public Criteria andProjectIdIsNull() {
addCriterion("scenario_id is null"); addCriterion("project_id is null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIsNotNull() { public Criteria andProjectIdIsNotNull() {
addCriterion("scenario_id is not null"); addCriterion("project_id is not null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdEqualTo(String value) { public Criteria andProjectIdEqualTo(String value) {
addCriterion("scenario_id =", value, "scenarioId"); addCriterion("project_id =", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotEqualTo(String value) { public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("scenario_id <>", value, "scenarioId"); addCriterion("project_id <>", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdGreaterThan(String value) { public Criteria andProjectIdGreaterThan(String value) {
addCriterion("scenario_id >", value, "scenarioId"); addCriterion("project_id >", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdGreaterThanOrEqualTo(String value) { public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("scenario_id >=", value, "scenarioId"); addCriterion("project_id >=", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLessThan(String value) { public Criteria andProjectIdLessThan(String value) {
addCriterion("scenario_id <", value, "scenarioId"); addCriterion("project_id <", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLessThanOrEqualTo(String value) { public Criteria andProjectIdLessThanOrEqualTo(String value) {
addCriterion("scenario_id <=", value, "scenarioId"); addCriterion("project_id <=", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLike(String value) { public Criteria andProjectIdLike(String value) {
addCriterion("scenario_id like", value, "scenarioId"); addCriterion("project_id like", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotLike(String value) { public Criteria andProjectIdNotLike(String value) {
addCriterion("scenario_id not like", value, "scenarioId"); addCriterion("project_id not like", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIn(List<String> values) { public Criteria andProjectIdIn(List<String> values) {
addCriterion("scenario_id in", values, "scenarioId"); addCriterion("project_id in", values, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotIn(List<String> values) { public Criteria andProjectIdNotIn(List<String> values) {
addCriterion("scenario_id not in", values, "scenarioId"); addCriterion("project_id not in", values, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdBetween(String value1, String value2) { public Criteria andProjectIdBetween(String value1, String value2) {
addCriterion("scenario_id between", value1, value2, "scenarioId"); addCriterion("project_id between", value1, value2, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotBetween(String value1, String value2) { public Criteria andProjectIdNotBetween(String value1, String value2) {
addCriterion("scenario_id not between", value1, value2, "scenarioId"); addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this; return (Criteria) this;
} }
} }

View File

@ -174,73 +174,73 @@ public class ApiScenarioReportExample {
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIsNull() { public Criteria andProjectIdIsNull() {
addCriterion("scenario_id is null"); addCriterion("project_id is null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIsNotNull() { public Criteria andProjectIdIsNotNull() {
addCriterion("scenario_id is not null"); addCriterion("project_id is not null");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdEqualTo(String value) { public Criteria andProjectIdEqualTo(String value) {
addCriterion("scenario_id =", value, "scenarioId"); addCriterion("project_id =", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotEqualTo(String value) { public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("scenario_id <>", value, "scenarioId"); addCriterion("project_id <>", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdGreaterThan(String value) { public Criteria andProjectIdGreaterThan(String value) {
addCriterion("scenario_id >", value, "scenarioId"); addCriterion("project_id >", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdGreaterThanOrEqualTo(String value) { public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("scenario_id >=", value, "scenarioId"); addCriterion("project_id >=", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLessThan(String value) { public Criteria andProjectIdLessThan(String value) {
addCriterion("scenario_id <", value, "scenarioId"); addCriterion("project_id <", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLessThanOrEqualTo(String value) { public Criteria andProjectIdLessThanOrEqualTo(String value) {
addCriterion("scenario_id <=", value, "scenarioId"); addCriterion("project_id <=", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdLike(String value) { public Criteria andProjectIdLike(String value) {
addCriterion("scenario_id like", value, "scenarioId"); addCriterion("project_id like", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotLike(String value) { public Criteria andProjectIdNotLike(String value) {
addCriterion("scenario_id not like", value, "scenarioId"); addCriterion("project_id not like", value, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdIn(List<String> values) { public Criteria andProjectIdIn(List<String> values) {
addCriterion("scenario_id in", values, "scenarioId"); addCriterion("project_id in", values, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotIn(List<String> values) { public Criteria andProjectIdNotIn(List<String> values) {
addCriterion("scenario_id not in", values, "scenarioId"); addCriterion("project_id not in", values, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdBetween(String value1, String value2) { public Criteria andProjectIdBetween(String value1, String value2) {
addCriterion("scenario_id between", value1, value2, "scenarioId"); addCriterion("project_id between", value1, value2, "projectId");
return (Criteria) this; return (Criteria) this;
} }
public Criteria andScenarioIdNotBetween(String value1, String value2) { public Criteria andProjectIdNotBetween(String value1, String value2) {
addCriterion("scenario_id not between", value1, value2, "scenarioId"); addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this; return (Criteria) this;
} }

View File

@ -3,7 +3,7 @@
<mapper namespace="io.metersphere.base.mapper.ApiScenarioReportDetailMapper"> <mapper namespace="io.metersphere.base.mapper.ApiScenarioReportDetailMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiScenarioReportDetail"> <resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiScenarioReportDetail">
<id column="report_id" jdbcType="VARCHAR" property="reportId" /> <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>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenarioReportDetail"> <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.ApiScenarioReportDetail">
<result column="content" jdbcType="LONGVARBINARY" property="content" /> <result column="content" jdbcType="LONGVARBINARY" property="content" />
@ -67,7 +67,7 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
report_id, scenario_id report_id, project_id
</sql> </sql>
<sql id="Blob_Column_List"> <sql id="Blob_Column_List">
content content
@ -121,9 +121,9 @@
</if> </if>
</delete> </delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail"> <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>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail"> <insert id="insertSelective" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
@ -132,8 +132,8 @@
<if test="reportId != null"> <if test="reportId != null">
report_id, report_id,
</if> </if>
<if test="scenarioId != null"> <if test="projectId != null">
scenario_id, project_id,
</if> </if>
<if test="content != null"> <if test="content != null">
content, content,
@ -143,8 +143,8 @@
<if test="reportId != null"> <if test="reportId != null">
#{reportId,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR},
</if> </if>
<if test="scenarioId != null"> <if test="projectId != null">
#{scenarioId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR},
</if> </if>
<if test="content != null"> <if test="content != null">
#{content,jdbcType=LONGVARBINARY}, #{content,jdbcType=LONGVARBINARY},
@ -163,8 +163,8 @@
<if test="record.reportId != null"> <if test="record.reportId != null">
report_id = #{record.reportId,jdbcType=VARCHAR}, report_id = #{record.reportId,jdbcType=VARCHAR},
</if> </if>
<if test="record.scenarioId != null"> <if test="record.projectId != null">
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR},
</if> </if>
<if test="record.content != null"> <if test="record.content != null">
content = #{record.content,jdbcType=LONGVARBINARY}, content = #{record.content,jdbcType=LONGVARBINARY},
@ -177,7 +177,7 @@
<update id="updateByExampleWithBLOBs" parameterType="map"> <update id="updateByExampleWithBLOBs" parameterType="map">
update api_scenario_report_detail update api_scenario_report_detail
set report_id = #{record.reportId,jdbcType=VARCHAR}, set report_id = #{record.reportId,jdbcType=VARCHAR},
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR},
content = #{record.content,jdbcType=LONGVARBINARY} content = #{record.content,jdbcType=LONGVARBINARY}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
@ -186,7 +186,7 @@
<update id="updateByExample" parameterType="map"> <update id="updateByExample" parameterType="map">
update api_scenario_report_detail update api_scenario_report_detail
set report_id = #{record.reportId,jdbcType=VARCHAR}, set report_id = #{record.reportId,jdbcType=VARCHAR},
scenario_id = #{record.scenarioId,jdbcType=VARCHAR} project_id = #{record.projectId,jdbcType=VARCHAR}
<if test="_parameter != null"> <if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" /> <include refid="Update_By_Example_Where_Clause" />
</if> </if>
@ -194,8 +194,8 @@
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail"> <update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
update api_scenario_report_detail update api_scenario_report_detail
<set> <set>
<if test="scenarioId != null"> <if test="projectId != null">
scenario_id = #{scenarioId,jdbcType=VARCHAR}, project_id = #{projectId,jdbcType=VARCHAR},
</if> </if>
<if test="content != null"> <if test="content != null">
content = #{content,jdbcType=LONGVARBINARY}, content = #{content,jdbcType=LONGVARBINARY},
@ -205,13 +205,13 @@
</update> </update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail"> <update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
update api_scenario_report_detail update api_scenario_report_detail
set scenario_id = #{scenarioId,jdbcType=VARCHAR}, set project_id = #{projectId,jdbcType=VARCHAR},
content = #{content,jdbcType=LONGVARBINARY} content = #{content,jdbcType=LONGVARBINARY}
where report_id = #{reportId,jdbcType=VARCHAR} where report_id = #{reportId,jdbcType=VARCHAR}
</update> </update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail"> <update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenarioReportDetail">
update api_scenario_report_detail update api_scenario_report_detail
set scenario_id = #{scenarioId,jdbcType=VARCHAR} set project_id = #{projectId,jdbcType=VARCHAR}
where report_id = #{reportId,jdbcType=VARCHAR} where report_id = #{reportId,jdbcType=VARCHAR}
</update> </update>
</mapper> </mapper>

View File

@ -3,7 +3,7 @@
<mapper namespace="io.metersphere.base.mapper.ApiScenarioReportMapper"> <mapper namespace="io.metersphere.base.mapper.ApiScenarioReportMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiScenarioReport"> <resultMap id="BaseResultMap" type="io.metersphere.base.domain.ApiScenarioReport">
<id column="id" jdbcType="VARCHAR" property="id" /> <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="name" jdbcType="VARCHAR" property="name" />
<result column="description" jdbcType="VARCHAR" property="description" /> <result column="description" jdbcType="VARCHAR" property="description" />
<result column="create_time" jdbcType="BIGINT" property="createTime" /> <result column="create_time" jdbcType="BIGINT" property="createTime" />
@ -71,7 +71,7 @@
</where> </where>
</sql> </sql>
<sql id="Base_Column_List"> <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 trigger_mode
</sql> </sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.ApiScenarioReportExample" resultMap="BaseResultMap"> <select id="selectByExample" parameterType="io.metersphere.base.domain.ApiScenarioReportExample" resultMap="BaseResultMap">
@ -105,11 +105,11 @@
</if> </if>
</delete> </delete>
<insert id="insert" parameterType="io.metersphere.base.domain.ApiScenarioReport"> <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, description, create_time, update_time,
`status`, user_id, trigger_mode `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}, #{description,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{status,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR} #{status,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR}, #{triggerMode,jdbcType=VARCHAR}
) )
@ -120,8 +120,8 @@
<if test="id != null"> <if test="id != null">
id, id,
</if> </if>
<if test="scenarioId != null"> <if test="projectId != null">
scenario_id, project_id,
</if> </if>
<if test="name != null"> <if test="name != null">
`name`, `name`,
@ -149,8 +149,8 @@
<if test="id != null"> <if test="id != null">
#{id,jdbcType=VARCHAR}, #{id,jdbcType=VARCHAR},
</if> </if>
<if test="scenarioId != null"> <if test="projectId != null">
#{scenarioId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR},
</if> </if>
<if test="name != null"> <if test="name != null">
#{name,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR},
@ -187,8 +187,8 @@
<if test="record.id != null"> <if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR}, id = #{record.id,jdbcType=VARCHAR},
</if> </if>
<if test="record.scenarioId != null"> <if test="record.projectId != null">
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR},
</if> </if>
<if test="record.name != null"> <if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR}, `name` = #{record.name,jdbcType=VARCHAR},
@ -219,7 +219,7 @@
<update id="updateByExample" parameterType="map"> <update id="updateByExample" parameterType="map">
update api_scenario_report update api_scenario_report
set id = #{record.id,jdbcType=VARCHAR}, set id = #{record.id,jdbcType=VARCHAR},
scenario_id = #{record.scenarioId,jdbcType=VARCHAR}, project_id = #{record.projectId,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR}, `name` = #{record.name,jdbcType=VARCHAR},
description = #{record.description,jdbcType=VARCHAR}, description = #{record.description,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT}, create_time = #{record.createTime,jdbcType=BIGINT},
@ -234,8 +234,8 @@
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReport"> <update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.ApiScenarioReport">
update api_scenario_report update api_scenario_report
<set> <set>
<if test="scenarioId != null"> <if test="projectId != null">
scenario_id = #{scenarioId,jdbcType=VARCHAR}, project_id = #{projectId,jdbcType=VARCHAR},
</if> </if>
<if test="name != null"> <if test="name != null">
`name` = #{name,jdbcType=VARCHAR}, `name` = #{name,jdbcType=VARCHAR},
@ -263,7 +263,7 @@
</update> </update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenarioReport"> <update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.ApiScenarioReport">
update api_scenario_report update api_scenario_report
set scenario_id = #{scenarioId,jdbcType=VARCHAR}, set project_id = #{projectId,jdbcType=VARCHAR},
`name` = #{name,jdbcType=VARCHAR}, `name` = #{name,jdbcType=VARCHAR},
description = #{description,jdbcType=VARCHAR}, description = #{description,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT}, create_time = #{createTime,jdbcType=BIGINT},

View File

@ -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);
}

View File

@ -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"'>
&gt; #{${object}.value}
</when>
<when test='${object}.operator == "lt"'>
&lt; #{${object}.value}
</when>
<when test='${object}.operator == "ge"'>
&gt;= #{${object}.value}
</when>
<when test='${object}.operator == "le"'>
&lt;= #{${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>

View File

@ -83,4 +83,10 @@ public class ProjectController {
public void updateProject(@RequestBody Project Project) { public void updateProject(@RequestBody Project Project) {
projectService.updateProject(Project); projectService.updateProject(Project);
} }
@PostMapping("/search")
public List<ProjectDTO> searchProject(@RequestBody ProjectRequest projectRequest) {
projectRequest.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
return projectService.getProjectList(projectRequest);
}
} }

View File

@ -64,10 +64,8 @@
<!--要生成的数据库表 --> <!--要生成的数据库表 -->
<table tableName="schedule"/> <table tableName="api_scenario_report"/>
<table tableName="notice"/> <table tableName="api_scenario_report_detail"/>
<table tableName="message_task"/>
<table tableName="test_plan"/>
</context> </context>
</generatorConfiguration> </generatorConfiguration>

View File

@ -4,11 +4,11 @@
<el-card> <el-card>
<section class="report-container" v-if="this.report.testId"> <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"> <main v-if="this.isNotRunning">
<ms-metric-chart :content="content" :totalTime="totalTime"/> <ms-metric-chart :content="content" :totalTime="totalTime"/>
<div @click="active"> <div>
<ms-scenario-results :scenarios="content.scenarios" v-on:requestResult="requestResult"/> <ms-scenario-results :scenarios="content.scenarios" v-on:requestResult="requestResult"/>
</div> </div>
<el-collapse-transition> <el-collapse-transition>
@ -64,10 +64,14 @@
requestType: undefined, requestType: undefined,
} }
}, },
props: ['reportId'],
activated() { activated() {
this.isRequestResult = false; this.isRequestResult = false;
}, },
props: {
reportId: String,
currentProjectId: String,
infoDb: Boolean,
},
watch: { watch: {
reportId() { reportId() {
this.getReport(); this.getReport();
@ -91,7 +95,7 @@
getReport() { getReport() {
this.init(); this.init();
if (this.reportId) { 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.$get(url, response => {
this.report = response.data || {}; this.report = response.data || {};
if (response.data) { if (response.data) {
@ -99,7 +103,6 @@
try { try {
this.content = JSON.parse(this.report.content); this.content = JSON.parse(this.report.content);
} catch (e) { } catch (e) {
// console.log(this.report.content)
throw e; throw e;
} }
this.getFails(); this.getFails();
@ -136,6 +139,7 @@
} }
}, },
requestResult(requestResult) { requestResult(requestResult) {
this.active();
this.isRequestResult = false; this.isRequestResult = false;
this.requestType = undefined; this.requestType = undefined;
if (requestResult.request.body.indexOf('[Callable Statement]') > -1) { if (requestResult.request.body.indexOf('[Callable Statement]') > -1) {
@ -155,6 +159,27 @@
reset(); 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() { exportReportReset() {
this.$router.go(0); this.$router.go(0);
} }

View File

@ -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>

View File

@ -2,13 +2,17 @@
<header class="report-header"> <header class="report-header">
<el-row> <el-row>
<el-col> <el-col>
<span>{{ report.projectName === null || report.projectName ==='' ? "场景执行报告": report.projectName}} / </span> <span><el-input size="mini" style="width: 200px" v-model="report.name"/> </span>
<router-link :to="path">{{ report.testName }}</router-link>
<span class="time"> {{ report.createTime | timestampFormatDate }}</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')}} {{$t('test_track.plan_view.export_report')}}
</el-button> </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-col>
</el-row> </el-row>
</header> </header>
@ -38,6 +42,9 @@
methods: { methods: {
handleExport(name) { handleExport(name) {
this.$emit('reportExport', name); this.$emit('reportExport', name);
},
handleSave(name) {
this.$emit('reportSave', name);
} }
} }
} }

View File

@ -1,10 +1,24 @@
<template> <template>
<div class="scenario-result"> <div class="scenario-result">
<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"> <div v-for="(request, index) in scenario.requestResults" :key="index">
<ms-request-result :key="index" :request="request" :indexNumber="index" <ms-request-result :key="index" :request="request" :indexNumber="index"
v-on:requestResult="requestResult" v-on:requestResult="requestResult"
:scenarioName="scenario.name"/> :scenarioName="scenario.name"/>
</div> </div>
</div>
</el-collapse-transition>
</div> </div>
</template> </template>

View File

@ -1,4 +1,5 @@
<template> <template>
<div>
<el-card class="table-card" v-loading="result.loading"> <el-card class="table-card" v-loading="result.loading">
<template v-slot:header> <template v-slot:header>
<ms-table-header :condition.sync="condition" @search="search" title="" <ms-table-header :condition.sync="condition" @search="search" title=""
@ -56,7 +57,16 @@
</el-table> </el-table>
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize" <ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/> :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> </el-card>
</div>
</template> </template>
<script> <script>
@ -65,10 +75,11 @@
import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn"; import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn";
import MsTag from "../../../common/components/MsTag"; import MsTag from "../../../common/components/MsTag";
import {getUUID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import MsApiReportDetail from "../report/ApiReportDetail";
export default { export default {
name: "MsApiScenarioList", name: "MsApiScenarioList",
components: {ShowMoreBtn, MsTablePagination, MsTableHeader, MsTag}, components: {ShowMoreBtn, MsTablePagination, MsTableHeader, MsTag, MsApiReportDetail},
props: { props: {
currentProject: Object, currentProject: Object,
currentModule: Object, currentModule: Object,
@ -83,6 +94,9 @@
currentPage: 1, currentPage: 1,
pageSize: 10, pageSize: 10,
total: 0, total: 0,
reportId: "",
runVisible: false,
runData: [],
buttons: [ buttons: [
{ {
name: this.$t('api_test.automation.batch_add_plan'), handleClick: this.handleBatchAddCase name: this.$t('api_test.automation.batch_add_plan'), handleClick: this.handleBatchAddCase
@ -140,7 +154,16 @@
}, },
handleBatchExecute() { 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() { selectAllChange() {
this.handleCommand("table"); this.handleCommand("table");
@ -156,7 +179,17 @@
this.$emit('edit', row); this.$emit('edit', row);
}, },
execute(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) { copy(row) {
row.id = getUUID(); row.id = getUUID();

View File

@ -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>

View File

@ -261,7 +261,7 @@
@runRefresh="runRefresh" ref="runTest"/> @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%"> <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> </el-drawer>
</div> </div>
</el-card> </el-card>
@ -284,7 +284,7 @@
import {getUUID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig"; import ApiEnvironmentConfig from "../../definition/components/environment/ApiEnvironmentConfig";
import MsAddTag from "./AddTag"; import MsAddTag from "./AddTag";
import MsRun from "./Run"; import MsRun from "./DebugRun";
import MsImportApiScenario from "./ImportApiScenario"; import MsImportApiScenario from "./ImportApiScenario";
import MsApiScenarioComponent from "./ApiScenarioComponent"; import MsApiScenarioComponent from "./ApiScenarioComponent";
import MsApiReportDetail from "../report/ApiReportDetail"; import MsApiReportDetail from "../report/ApiReportDetail";
@ -333,7 +333,7 @@
expandedNode: [], expandedNode: [],
scenarioDefinition: [], scenarioDefinition: [],
path: "/api/automation/create", path: "/api/automation/create",
debugData: [], debugData: {},
reportId: "", reportId: "",
} }
}, },
@ -539,9 +539,7 @@
this.$error(this.$t('api_test.environment.select_environment')); this.$error(this.$t('api_test.environment.select_environment'));
return; return;
} }
let scenario = {id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario", referenced: 'Created', environmentId: this.currentEnvironmentId, hashTree: this.scenarioDefinition}; this.debugData = {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.reportId = getUUID().substring(0, 8); this.reportId = getUUID().substring(0, 8);
}, },
getEnvironments() { getEnvironments() {
@ -592,11 +590,68 @@
}); });
return path[0].path; 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() { editScenario() {
this.$refs['currentScenario'].validate((valid) => { this.$refs['currentScenario'].validate((valid) => {
if (valid) { if (valid) {
this.setParameter(); 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.$success(this.$t('commons.save_success'));
this.path = "/api/automation/update"; this.path = "/api/automation/update";
this.currentScenario.tagId = JSON.parse(this.currentScenario.tagId); this.currentScenario.tagId = JSON.parse(this.currentScenario.tagId);

View File

@ -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>

View File

@ -12,12 +12,7 @@ export const TYPE = "TestPlan";
export default class TestPlan extends HashTreeElement { export default class TestPlan extends HashTreeElement {
constructor(options = DEFAULT_OPTIONS) { constructor(options = DEFAULT_OPTIONS) {
super(options); super(options);
this.$type = TYPE;
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.hashTree = [];
this.userDefinedVariables = []; this.userDefinedVariables = [];

View File

@ -11,21 +11,7 @@ export const TYPE = "ThreadGroup";
export default class ThreadGroup extends HashTreeElement { export default class ThreadGroup extends HashTreeElement {
constructor(options = DEFAULT_OPTIONS) { constructor(options = DEFAULT_OPTIONS) {
super(options); super(options);
this.$type = TYPE;
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');
} }
} }

View File

@ -3,6 +3,18 @@
<el-row type="flex"> <el-row type="flex">
<el-col :span="10"> <el-col :span="10">
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router :default-active='$route.path'> <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'"> <el-menu-item :index="'/api/home'">
{{ $t("i18n.home") }} {{ $t("i18n.home") }}
</el-menu-item> </el-menu-item>
@ -15,14 +27,9 @@
{{ $t("i18n.automation") }} {{ $t("i18n.automation") }}
</el-menu-item> </el-menu-item>
<el-submenu :class="{'deactivation':!isProjectActivation}" v-permission="['test_manager','test_user','test_viewer']" index="3"> <el-menu-item :index="'/api/automation/report'">
<template v-slot:title>{{ $t('commons.project') }}</template> {{ $t("i18n.report") }}
<ms-recent-list ref="projectRecent" :options="projectRecent"/> </el-menu-item>
<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-submenu v-permission="['test_manager','test_user','test_viewer']" index="4"> <el-submenu v-permission="['test_manager','test_user','test_viewer']" index="4">
<template v-slot:title>{{ $t('commons.test') }}</template> <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 MsCreateButton from "../../common/head/CreateButton";
import MsCreateTest from "../../common/head/CreateTest"; import MsCreateTest from "../../common/head/CreateTest";
import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent"; import {ApiEvent, LIST_CHANGE} from "@/business/components/common/head/ListEvent";
import SearchList from "@/business/components/common/head/SearchList";
export default { export default {
name: "MsApiHeaderMenus", name: "MsApiHeaderMenus",
components: {MsCreateTest, MsCreateButton, MsShowAll, MsRecentList}, components: {SearchList, MsCreateTest, MsCreateButton, MsShowAll, MsRecentList},
data() { data() {
return { return {
projectRecent: { projectRecent: {

View File

@ -48,6 +48,11 @@ export default {
path: "automation", path: "automation",
name: "ApiAutomation", name: "ApiAutomation",
component: () => import('@/business/components/api/automation/ApiAutomation'), component: () => import('@/business/components/api/automation/ApiAutomation'),
},
{
path: "automation/report",
name: "ApiReportList",
component: () => import('@/business/components/api/automation/report/ApiReportList'),
} }
] ]
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <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"> <slot name="title">
{{title}} {{title}}
</slot> </slot>

View File

@ -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>

View File

@ -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>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-menu-item :index="this.index" @click="changeRoute"> <el-menu-item :index="this.index">
<font-awesome-icon :icon="['fa', 'list-ul']"/> <font-awesome-icon :icon="['fa', 'list-ul']"/>
<span>{{ $t('commons.show_all') }}</span> <span>{{ $t('commons.show_all') }}</span>
</el-menu-item> </el-menu-item>
@ -10,14 +10,6 @@ export default {
name: "MsShowAll", name: "MsShowAll",
props: { props: {
index: String index: String
},
methods: {
changeRoute() {
//
if (this.$route.path === this.index) {
this.$router.replace({path: this.index, query: {type: 'all'}});
}
}
} }
} }
</script> </script>

View File

@ -3,20 +3,23 @@
<el-row type="flex"> <el-row type="flex">
<el-col :span="8"> <el-col :span="8">
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router :default-active='$route.path'> <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']" <el-submenu v-permission="['test_manager','test_user','test_viewer']"
index="3" popper-class="submenu"> index="3" popper-class="submenu">
<template v-slot:title>{{ $t('commons.project') }}</template> <template v-slot:title>{{ $t('commons.project') }}</template>
<ms-recent-list ref="projectRecent" :options="projectRecent"/> <search-list ref="projectRecent" :options="projectRecent"/>
<el-divider/> <el-divider/>
<ms-show-all :index="'/performance/project/all'"/> <el-menu-item :index="'/performance/project/create'">
<ms-create-button v-permission="['test_manager','test_user']" :index="'/performance/project/create'" <font-awesome-icon :icon="['fa', 'plus']"/>
:title="$t('project.create')"/> <span style="padding-left: 7px;">创建项目</span>
</el-menu-item>
<ms-show-all :index="'/setting/project'"/>
</el-submenu> </el-submenu>
<el-menu-item :index="'/performance/home'">
{{ $t("i18n.home") }}
</el-menu-item>
<el-submenu v-permission="['test_manager','test_user','test_viewer']" <el-submenu v-permission="['test_manager','test_user','test_viewer']"
index="4" popper-class="submenu"> index="4" popper-class="submenu">
<template v-slot:title>{{ $t('commons.test') }}</template> <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 MsCreateButton from "../../common/head/CreateButton";
import MsShowAll from "../../common/head/ShowAll"; import MsShowAll from "../../common/head/ShowAll";
import {LIST_CHANGE, PerformanceEvent} from "@/business/components/common/head/ListEvent"; import {LIST_CHANGE, PerformanceEvent} from "@/business/components/common/head/ListEvent";
import SearchList from "@/business/components/common/head/SearchList";
export default { export default {
name: "PerformanceHeaderMenus", name: "PerformanceHeaderMenus",
components: { components: {
SearchList,
MsCreateButton, MsCreateButton,
MsShowAll, MsShowAll,
MsRecentList, MsRecentList,
@ -92,7 +97,8 @@ export default {
}, },
router(item) { router(item) {
} }
} },
input2: ''
} }
}, },
methods: { methods: {

View File

@ -4,7 +4,7 @@
<el-card class="table-card" v-loading="result.loading"> <el-card class="table-card" v-loading="result.loading">
<template v-slot:header> <template v-slot:header>
<ms-table-header :is-tester-permission="true" :condition.sync="condition" @search="search" @create="create" <ms-table-header :is-tester-permission="true" :condition.sync="condition" @search="search" @create="create"
:create-tip="btnTips" :title="title"/> :create-tip="btnTips" title=""/>
</template> </template>
<el-table border class="adjust-table" @row-click="link" :data="items" style="width: 100%" @sort-change="sort"> <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/> <el-table-column prop="name" :label="$t('commons.name')" width="250" show-overflow-tooltip/>
@ -36,7 +36,7 @@
<template v-slot:default="scope"> <template v-slot:default="scope">
<ms-table-operator :is-tester-permission="true" @editClick="edit(scope.row)" <ms-table-operator :is-tester-permission="true" @editClick="edit(scope.row)"
@deleteClick="handleDelete(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" <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)"/> type="info" @exec="openEnvironmentConfig(scope.row)"/>
</template> </template>
@ -188,7 +188,6 @@ export default {
this.createVisible = true; this.createVisible = true;
listenGoBack(this.handleClose); listenGoBack(this.handleClose);
this.form = Object.assign({}, row); this.form = Object.assign({}, row);
if (this.baseUrl === 'track') {
this.$get("/service/integration/all/" + getCurrentUser().lastOrganizationId, response => { this.$get("/service/integration/all/" + getCurrentUser().lastOrganizationId, response => {
let data = response.data; let data = response.data;
let platforms = data.map(d => d.platform); let platforms = data.map(d => d.platform);
@ -202,7 +201,6 @@ export default {
this.zentao = true; this.zentao = true;
} }
}); });
}
}, },
submit(formName) { submit(formName) {

View File

@ -41,6 +41,14 @@
</el-menu-item> </el-menu-item>
</el-submenu> </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> </el-menu>
</template> </template>
@ -73,6 +81,7 @@
organizations: getMenus('organization'), organizations: getMenus('organization'),
workspaces: getMenus('workspace'), workspaces: getMenus('workspace'),
persons: getMenus('person'), persons: getMenus('person'),
project: getMenus('project'),
isCurrentOrganizationAdmin: false, isCurrentOrganizationAdmin: false,
isCurrentWorkspaceUser: false, isCurrentWorkspaceUser: false,
} }

View File

@ -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>

View File

@ -79,6 +79,11 @@ export default {
roles: ['test_manager', 'test_user', 'test_viewer', 'org_admin', 'admin'] roles: ['test_manager', 'test_user', 'test_viewer', 'org_admin', 'admin']
} }
}, },
{
path: 'project',
component: () => import('@/business/components/settings/project/Project'),
meta: {project: true, title: '项目管理'}
},
] ]
} }

View File

@ -5,19 +5,22 @@
<el-col :span="12"> <el-col :span="12">
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router <el-menu class="header-menu" :unique-opened="true" mode="horizontal" router
:default-active='$route.path'> :default-active='$route.path'>
<el-menu-item :index="'/track/home'">
{{ $t("i18n.home") }}
</el-menu-item>
<el-submenu :class="{'deactivation':!isProjectActivation}" <el-submenu :class="{'deactivation':!isProjectActivation}"
v-permission="['test_manager','test_user','test_viewer']" index="3" popper-class="submenu"> v-permission="['test_manager','test_user','test_viewer']" index="3" popper-class="submenu">
<template v-slot:title>{{ $t('commons.project') }}</template> <template v-slot:title>{{ $t('commons.project') }}</template>
<ms-recent-list ref="projectRecent" :options="projectRecent"/> <search-list ref="projectRecent" :options="projectRecent"/>
<el-divider/> <el-divider/>
<ms-show-all :index="'/track/project/all'"/> <el-menu-item :index="'/performance/project/create'">
<ms-create-button v-permission="['test_manager','test_user']" :index="'/track/project/create'" <font-awesome-icon :icon="['fa', 'plus']"/>
:title="$t('project.create')"/> <span style="padding-left: 7px;">创建项目</span>
</el-menu-item>
<ms-show-all :index="'/setting/project'"/>
</el-submenu> </el-submenu>
<el-menu-item :index="'/track/home'">
{{ $t("i18n.home") }}
</el-menu-item>
<el-submenu v-permission="['test_manager','test_user','test_viewer']" <el-submenu v-permission="['test_manager','test_user','test_viewer']"
index="6" popper-class="submenu"> index="6" popper-class="submenu">
<template v-slot:title>{{ $t('test_track.case.test_case') }}</template> <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 MsRecentList from "../../common/head/RecentList";
import MsCreateButton from "../../common/head/CreateButton"; import MsCreateButton from "../../common/head/CreateButton";
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent"; import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
import SearchList from "@/business/components/common/head/SearchList";
export default { export default {
name: "TrackHeaderMenus", name: "TrackHeaderMenus",
components: {MsShowAll, MsRecentList, MsCreateButton}, components: {SearchList, MsShowAll, MsRecentList, MsCreateButton},
data() { data() {
return { return {
testPlanViewPath: '', testPlanViewPath: '',

@ -1 +1 @@
Subproject commit a22a3005d9bd254793fcf634d72539cbdf31be3a Subproject commit 8a972a198775b3783ed6e4cef27197e53d1ebdc8

View File

@ -28,7 +28,7 @@ export const xpack = {
function checkLicense(el, binding, type) { function checkLicense(el, binding, type) {
let v = hasLicense() let v = hasLicense()
if (v) { if (!v) {
el.parentNode && el.parentNode.removeChild(el) el.parentNode && el.parentNode.removeChild(el)
} }
} }

View File

@ -163,7 +163,7 @@ export default {
current_user: "Current user" current_user: "Current user"
} }
}, },
monitor:"monitor" monitor: "monitor"
}, },
license: { license: {
title: 'Authorization management', title: 'Authorization management',
@ -543,6 +543,7 @@ export default {
customize_script: "Custom script", customize_script: "Custom script",
customize_req: "Custom request", customize_req: "Custom request",
reference_info: "Please select interface or use case", reference_info: "Please select interface or use case",
report_name_info: 'Please enter the registration name',
}, },
environment: { environment: {
name: "Environment Name", name: "Environment Name",
@ -779,14 +780,14 @@ export default {
not_exist: "Test report does not exist", not_exist: "Test report does not exist",
}, },
api_monitor: { api_monitor: {
to:"to", to: "to",
start_time:"Start Time", start_time: "Start Time",
end_time:"End Time", end_time: "End Time",
today:"Today", today: "Today",
this_week:"This Week", this_week: "This Week",
this_mouth:"This Mouth", this_mouth: "This Mouth",
please_search:"Please Search", please_search: "Please Search",
date:"Date" date: "Date"
}, },
test_track: { test_track: {
test_track: "Track", test_track: "Track",
@ -1096,6 +1097,7 @@ export default {
home: 'Home', home: 'Home',
definition: 'Api Definition', definition: 'Api Definition',
automation: 'Api Automation', automation: 'Api Automation',
report: 'Test report',
}, },
ldap: { ldap: {
url: 'LDAP URL', url: 'LDAP URL',

View File

@ -570,7 +570,8 @@ export default {
follow_people: "关注人", follow_people: "关注人",
select_table: "选择可见数据", select_table: "选择可见数据",
select_all: "选择全部数据" select_all: "选择全部数据"
} },
report_name_info: '请输入报名名称',
}, },
environment: { environment: {
name: "环境名称", name: "环境名称",
@ -809,14 +810,14 @@ export default {
not_exist: "测试报告不存在", not_exist: "测试报告不存在",
}, },
api_monitor: { 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: "日期"
}, },
test_track: { test_track: {
test_track: "测试跟踪", test_track: "测试跟踪",
@ -1125,6 +1126,7 @@ export default {
home: '首页', home: '首页',
definition: '接口定义', definition: '接口定义',
automation: '接口自动化', automation: '接口自动化',
report: '测试报告',
}, },
ldap: { ldap: {
url: 'LDAP地址', url: 'LDAP地址',

View File

@ -543,8 +543,8 @@ export default {
scenario_import: "場景導入", scenario_import: "場景導入",
customize_script: "自定義腳本", customize_script: "自定義腳本",
customize_req: "自定義請求", customize_req: "自定義請求",
reference_info: "請選擇接口或用例" reference_info: "請選擇接口或用例",
report_name_info: '请输入报名名称',
}, },
environment: { environment: {
name: "環境名稱", name: "環境名稱",
@ -1098,6 +1098,7 @@ export default {
home: '首頁', home: '首頁',
definition: '接口定義', definition: '接口定義',
automation: '接口自動化', automation: '接口自動化',
report: '測試報告',
}, },
ldap: { ldap: {
url: 'LDAP地址', url: 'LDAP地址',