Merge branch 'v1.8' of https://github.com/metersphere/metersphere into v1.8
This commit is contained in:
commit
ca67a3ed56
|
@ -7,12 +7,12 @@ import io.metersphere.api.dto.definition.*;
|
||||||
import io.metersphere.api.service.ApiTestCaseService;
|
import io.metersphere.api.service.ApiTestCaseService;
|
||||||
import io.metersphere.base.domain.ApiTestCase;
|
import io.metersphere.base.domain.ApiTestCase;
|
||||||
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
|
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
|
||||||
import io.metersphere.commons.constants.ApiRunMode;
|
|
||||||
import io.metersphere.commons.constants.RoleConstants;
|
import io.metersphere.commons.constants.RoleConstants;
|
||||||
import io.metersphere.commons.utils.PageUtils;
|
import io.metersphere.commons.utils.PageUtils;
|
||||||
import io.metersphere.commons.utils.Pager;
|
import io.metersphere.commons.utils.Pager;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
|
import io.metersphere.track.request.testcase.ApiCaseRelevanceRequest;
|
||||||
|
import io.metersphere.track.service.TestPlanApiCaseService;
|
||||||
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.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
@ -29,7 +29,8 @@ public class ApiTestCaseController {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ApiTestCaseService apiTestCaseService;
|
private ApiTestCaseService apiTestCaseService;
|
||||||
|
@Resource
|
||||||
|
private TestPlanApiCaseService testPlanApiCaseService;
|
||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
public List<ApiTestCaseResult> list(@RequestBody ApiTestCaseRequest request) {
|
public List<ApiTestCaseResult> list(@RequestBody ApiTestCaseRequest request) {
|
||||||
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
|
||||||
|
@ -48,6 +49,12 @@ public class ApiTestCaseController {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@GetMapping("/getStateByTestPlan/{id}")
|
||||||
|
public String getStateByTestPlan(@PathVariable String id ) {
|
||||||
|
String status=testPlanApiCaseService.getState(id);
|
||||||
|
return status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/list/{goPage}/{pageSize}")
|
@PostMapping("/list/{goPage}/{pageSize}")
|
||||||
public Pager<List<ApiTestCaseDTO>> listSimple(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiTestCaseRequest request) {
|
public Pager<List<ApiTestCaseDTO>> listSimple(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiTestCaseRequest request) {
|
||||||
|
@ -131,7 +138,8 @@ public class ApiTestCaseController {
|
||||||
return apiTestCaseService.run(request);
|
return apiTestCaseService.run(request);
|
||||||
}
|
}
|
||||||
@GetMapping(value = "/jenkins/exec/result/{id}")
|
@GetMapping(value = "/jenkins/exec/result/{id}")
|
||||||
public String getExecResult(@PathVariable String id) {
|
public String getExecResult(@PathVariable String id) {
|
||||||
return apiTestCaseService.getExecResult(id);
|
return apiTestCaseService.getExecResult(id);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -75,6 +75,8 @@ import org.apache.jorphan.collections.HashTree;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
||||||
|
@ -132,12 +134,66 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
||||||
return (HashTree) field.get(scriptWrapper);
|
return (HashTree) field.get(scriptWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isProtocolDefaultPort(HTTPSamplerProxy source) {
|
||||||
|
String portAsString = source.getPropertyAsString("HTTPSampler.port");
|
||||||
|
if (portAsString != null && !portAsString.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String url(String protocol, String host, String port, String file) {
|
||||||
|
protocol = protocol.toLowerCase();
|
||||||
|
if (StringUtils.isNotEmpty(file) && !file.startsWith("/")) {
|
||||||
|
file += "/";
|
||||||
|
}
|
||||||
|
return protocol + "://" + host + ":" + port + file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl(HTTPSamplerProxy source) throws MalformedURLException {
|
||||||
|
String path = source.getPath();
|
||||||
|
if (!path.startsWith("http://") && !path.startsWith("https://")) {
|
||||||
|
String domain = source.getDomain();
|
||||||
|
String protocol = source.getProtocol();
|
||||||
|
String method = source.getMethod();
|
||||||
|
StringBuilder pathAndQuery = new StringBuilder(100);
|
||||||
|
if ("file".equalsIgnoreCase(protocol)) {
|
||||||
|
domain = null;
|
||||||
|
} else if (!path.startsWith("/")) {
|
||||||
|
pathAndQuery.append('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
pathAndQuery.append(path);
|
||||||
|
if ("GET".equals(method) || "DELETE".equals(method) || "OPTIONS".equals(method)) {
|
||||||
|
String queryString = source.getQueryString(source.getContentEncoding());
|
||||||
|
if (queryString.length() > 0) {
|
||||||
|
if (path.contains("?")) {
|
||||||
|
pathAndQuery.append("&");
|
||||||
|
} else {
|
||||||
|
pathAndQuery.append("?");
|
||||||
|
}
|
||||||
|
|
||||||
|
pathAndQuery.append(queryString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String portAsString = source.getPropertyAsString("HTTPSampler.port");
|
||||||
|
return this.isProtocolDefaultPort(source) ? new URL(protocol, domain, pathAndQuery.toString()).toExternalForm() : this.url(protocol, domain, portAsString, pathAndQuery.toString());
|
||||||
|
} else {
|
||||||
|
return new URL(path).toExternalForm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void convertHttpSampler(MsHTTPSamplerProxy samplerProxy, Object key) {
|
private void convertHttpSampler(MsHTTPSamplerProxy samplerProxy, Object key) {
|
||||||
try {
|
try {
|
||||||
HTTPSamplerProxy source = (HTTPSamplerProxy) key;
|
HTTPSamplerProxy source = (HTTPSamplerProxy) key;
|
||||||
BeanUtils.copyBean(samplerProxy, source);
|
BeanUtils.copyBean(samplerProxy, source);
|
||||||
samplerProxy.setRest(new ArrayList<KeyValue>(){{this.add(new KeyValue());}});
|
samplerProxy.setRest(new ArrayList<KeyValue>() {{
|
||||||
samplerProxy.setArguments(new ArrayList<KeyValue>(){{this.add(new KeyValue());}});
|
this.add(new KeyValue());
|
||||||
|
}});
|
||||||
|
samplerProxy.setArguments(new ArrayList<KeyValue>() {{
|
||||||
|
this.add(new KeyValue());
|
||||||
|
}});
|
||||||
if (source != null && source.getHTTPFiles().length > 0) {
|
if (source != null && source.getHTTPFiles().length > 0) {
|
||||||
samplerProxy.getBody().initBinary();
|
samplerProxy.getBody().initBinary();
|
||||||
samplerProxy.getBody().setType(Body.FORM_DATA);
|
samplerProxy.getBody().setType(Body.FORM_DATA);
|
||||||
|
@ -158,7 +214,8 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
||||||
samplerProxy.getBody().setKvs(keyValues);
|
samplerProxy.getBody().setKvs(keyValues);
|
||||||
}
|
}
|
||||||
samplerProxy.setProtocol(RequestType.HTTP);
|
samplerProxy.setProtocol(RequestType.HTTP);
|
||||||
samplerProxy.setPort(source.getPort() + "");
|
samplerProxy.setPort(source.getPropertyAsString("HTTPSampler.port"));
|
||||||
|
samplerProxy.setDomain(source.getDomain());
|
||||||
if (source.getArguments() != null) {
|
if (source.getArguments() != null) {
|
||||||
if (source.getPostBodyRaw()) {
|
if (source.getPostBodyRaw()) {
|
||||||
samplerProxy.getBody().setType(Body.RAW);
|
samplerProxy.getBody().setType(Body.RAW);
|
||||||
|
@ -178,10 +235,10 @@ public class MsJmeterParser extends ApiImportAbstractParser<ScenarioImport> {
|
||||||
}
|
}
|
||||||
samplerProxy.getBody().initBinary();
|
samplerProxy.getBody().initBinary();
|
||||||
}
|
}
|
||||||
samplerProxy.setPath("");
|
// samplerProxy.setPath(source.getPath());
|
||||||
samplerProxy.setMethod(source.getMethod());
|
samplerProxy.setMethod(source.getMethod());
|
||||||
if (source.getUrl() != null) {
|
if (this.getUrl(source) != null) {
|
||||||
samplerProxy.setUrl(source.getUrl().toString());
|
samplerProxy.setUrl(this.getUrl(source));
|
||||||
}
|
}
|
||||||
samplerProxy.setId(UUID.randomUUID().toString());
|
samplerProxy.setId(UUID.randomUUID().toString());
|
||||||
samplerProxy.setType("HTTPSamplerProxy");
|
samplerProxy.setType("HTTPSamplerProxy");
|
||||||
|
|
|
@ -91,6 +91,9 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
@JSONField(ordinal = 36)
|
@JSONField(ordinal = 36)
|
||||||
private MsAuthManager authManager;
|
private MsAuthManager authManager;
|
||||||
|
|
||||||
|
@JSONField(ordinal = 37)
|
||||||
|
private boolean urlOrPath;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
public void toHashTree(HashTree tree, List<MsTestElement> hashTree, ParameterConfig config) {
|
||||||
// 非导出操作,且不是启用状态则跳过执行
|
// 非导出操作,且不是启用状态则跳过执行
|
||||||
|
@ -140,23 +143,26 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
url = this.getUrl();
|
url = this.getUrl();
|
||||||
isUrl = true;
|
isUrl = true;
|
||||||
}
|
}
|
||||||
URL urlObject = new URL(url);
|
|
||||||
if (isUrl) {
|
if (isUrl) {
|
||||||
|
if (StringUtils.isNotEmpty(this.getPort()) && this.getPort().startsWith("${")) {
|
||||||
|
url.replaceAll(this.getPort(), "10990");
|
||||||
|
}
|
||||||
|
URL urlObject = new URL(url);
|
||||||
sampler.setDomain(URLDecoder.decode(urlObject.getHost(), "UTF-8"));
|
sampler.setDomain(URLDecoder.decode(urlObject.getHost(), "UTF-8"));
|
||||||
if (urlObject.getPort() > 0) {
|
if (urlObject.getPort() > 0 && urlObject.getPort() != 10990 && StringUtils.isNotEmpty(this.getPort()) && this.getPort().startsWith("${")) {
|
||||||
sampler.setPort(urlObject.getPort());
|
sampler.setPort(urlObject.getPort());
|
||||||
|
} else {
|
||||||
|
sampler.setProperty("HTTPSampler.port", this.getPort());
|
||||||
}
|
}
|
||||||
sampler.setProtocol(urlObject.getProtocol());
|
sampler.setProtocol(urlObject.getProtocol());
|
||||||
|
sampler.setPath(urlObject.getPath());
|
||||||
} else {
|
} else {
|
||||||
sampler.setDomain(config.getConfig().get(this.getProjectId()).getHttpConfig().getDomain());
|
sampler.setDomain(config.getConfig().get(this.getProjectId()).getHttpConfig().getDomain());
|
||||||
sampler.setPort(config.getConfig().get(this.getProjectId()).getHttpConfig().getPort());
|
sampler.setPort(config.getConfig().get(this.getProjectId()).getHttpConfig().getPort());
|
||||||
sampler.setProtocol(config.getConfig().get(this.getProjectId()).getHttpConfig().getProtocol());
|
sampler.setProtocol(config.getConfig().get(this.getProjectId()).getHttpConfig().getProtocol());
|
||||||
|
sampler.setPath(this.getPath());
|
||||||
}
|
}
|
||||||
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
|
String envPath = sampler.getPath();
|
||||||
if (StringUtils.isNotBlank(this.getPath()) && !isUrl) {
|
|
||||||
envPath += this.getPath();
|
|
||||||
sampler.setPath(envPath);
|
|
||||||
}
|
|
||||||
if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) {
|
if (CollectionUtils.isNotEmpty(this.getRest()) && this.isRest()) {
|
||||||
envPath = getRestParameters(URLDecoder.decode(envPath, "UTF-8"));
|
envPath = getRestParameters(URLDecoder.decode(envPath, "UTF-8"));
|
||||||
sampler.setPath(envPath);
|
sampler.setPath(envPath);
|
||||||
|
@ -177,9 +183,16 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||||
url = "http://" + url;
|
url = "http://" + url;
|
||||||
}
|
}
|
||||||
|
if (StringUtils.isNotEmpty(this.getPort()) && this.getPort().startsWith("${")) {
|
||||||
|
url.replaceAll(this.getPort(), "10990");
|
||||||
|
}
|
||||||
URL urlObject = new URL(url);
|
URL urlObject = new URL(url);
|
||||||
sampler.setDomain(URLDecoder.decode(urlObject.getHost(), "UTF-8"));
|
sampler.setDomain(URLDecoder.decode(urlObject.getHost(), "UTF-8"));
|
||||||
sampler.setPort(urlObject.getPort());
|
if (urlObject.getPort() > 0 && urlObject.getPort() != 10990 && StringUtils.isNotEmpty(this.getPort()) && this.getPort().startsWith("${")) {
|
||||||
|
sampler.setPort(urlObject.getPort());
|
||||||
|
} else {
|
||||||
|
sampler.setProperty("HTTPSampler.port", this.getPort());
|
||||||
|
}
|
||||||
sampler.setProtocol(urlObject.getProtocol());
|
sampler.setProtocol(urlObject.getProtocol());
|
||||||
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
|
String envPath = StringUtils.equals(urlObject.getPath(), "/") ? "" : urlObject.getPath();
|
||||||
sampler.setPath(envPath);
|
sampler.setPath(envPath);
|
||||||
|
@ -327,10 +340,16 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isURL(String str) {
|
public boolean isURL(String str) {
|
||||||
//转换为小写
|
|
||||||
try {
|
try {
|
||||||
new URL(str);
|
String regex = "^((https|http|ftp|rtsp|mms)?://)"
|
||||||
return true;
|
+ "?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?"
|
||||||
|
+ "(([0-9]{1,3}\\.){3}[0-9]{1,3}" + "|" + "([0-9a-z_!~*'()-]+\\.)*"
|
||||||
|
+ "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\."
|
||||||
|
+ "[a-z]{2,6})"
|
||||||
|
+ "(:[0-9]{1,5})?"
|
||||||
|
+ "((/?)|"
|
||||||
|
+ "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$";
|
||||||
|
return str.matches(regex) || (str.matches("^(http|https|ftp)://.*$") && str.matches(".*://\\$\\{.*$"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -339,5 +358,5 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
||||||
private boolean isRest() {
|
private boolean isRest() {
|
||||||
return this.getRest().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).toArray().length > 0;
|
return this.getRest().stream().filter(KeyValue::isEnable).filter(KeyValue::isValid).toArray().length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
package io.metersphere.api.jmeter;
|
package io.metersphere.api.jmeter;
|
||||||
|
|
||||||
import io.metersphere.api.dto.definition.ApiTestCaseInfo;
|
|
||||||
import io.metersphere.api.dto.scenario.request.RequestType;
|
import io.metersphere.api.dto.scenario.request.RequestType;
|
||||||
import io.metersphere.api.service.*;
|
import io.metersphere.api.service.*;
|
||||||
import io.metersphere.base.domain.ApiDefinitionExecResult;
|
import io.metersphere.base.domain.ApiDefinitionExecResult;
|
||||||
import io.metersphere.base.domain.ApiScenarioReport;
|
import io.metersphere.base.domain.ApiScenarioReport;
|
||||||
import io.metersphere.base.domain.ApiTestReport;
|
import io.metersphere.base.domain.ApiTestReport;
|
||||||
import io.metersphere.base.domain.TestPlanReport;
|
|
||||||
import io.metersphere.commons.constants.*;
|
import io.metersphere.commons.constants.*;
|
||||||
import io.metersphere.commons.utils.CommonBeanFactory;
|
import io.metersphere.commons.utils.CommonBeanFactory;
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
import io.metersphere.commons.utils.LogUtil;
|
||||||
|
@ -16,7 +14,6 @@ import io.metersphere.notice.sender.NoticeModel;
|
||||||
import io.metersphere.notice.service.NoticeSendService;
|
import io.metersphere.notice.service.NoticeSendService;
|
||||||
import io.metersphere.service.SystemParameterService;
|
import io.metersphere.service.SystemParameterService;
|
||||||
import io.metersphere.track.service.TestPlanReportService;
|
import io.metersphere.track.service.TestPlanReportService;
|
||||||
import io.metersphere.track.service.TestPlanService;
|
|
||||||
import io.metersphere.track.service.TestPlanTestCaseService;
|
import io.metersphere.track.service.TestPlanTestCaseService;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -250,7 +247,10 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendTask(report, reportUrl, testResult);
|
if (StringUtils.equals(ReportTriggerMode.API.name(), report.getTriggerMode())||StringUtils.equals(ReportTriggerMode.SCHEDULE.name(), report.getTriggerMode())) {
|
||||||
|
sendTask(report, reportUrl, testResult);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sendTask(ApiTestReport report, String reportUrl, TestResult testResult) {
|
private static void sendTask(ApiTestReport report, String reportUrl, TestResult testResult) {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import io.metersphere.api.jmeter.JMeterService;
|
||||||
import io.metersphere.base.domain.*;
|
import io.metersphere.base.domain.*;
|
||||||
import io.metersphere.base.mapper.*;
|
import io.metersphere.base.mapper.*;
|
||||||
import io.metersphere.base.mapper.ext.*;
|
import io.metersphere.base.mapper.ext.*;
|
||||||
|
import io.metersphere.commons.constants.ApiRunMode;
|
||||||
import io.metersphere.commons.constants.TestPlanStatus;
|
import io.metersphere.commons.constants.TestPlanStatus;
|
||||||
import io.metersphere.commons.exception.MSException;
|
import io.metersphere.commons.exception.MSException;
|
||||||
import io.metersphere.commons.utils.*;
|
import io.metersphere.commons.utils.*;
|
||||||
|
@ -551,7 +552,14 @@ public class ApiTestCaseService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String run(RunCaseRequest request) {
|
public String run(RunCaseRequest request) {
|
||||||
ApiTestCaseWithBLOBs testCaseWithBLOBs = apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
|
ApiTestCaseWithBLOBs testCaseWithBLOBs=new ApiTestCaseWithBLOBs();
|
||||||
|
if(StringUtils.equals(request.getRunMode(), ApiRunMode.JENKINS_API_PLAN.name())){
|
||||||
|
testCaseWithBLOBs= apiTestCaseMapper.selectByPrimaryKey(request.getReportId());
|
||||||
|
request.setCaseId(request.getReportId());
|
||||||
|
}else{
|
||||||
|
testCaseWithBLOBs= apiTestCaseMapper.selectByPrimaryKey(request.getCaseId());
|
||||||
|
|
||||||
|
}
|
||||||
// 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取
|
// 多态JSON普通转换会丢失内容,需要通过 ObjectMapper 获取
|
||||||
if (testCaseWithBLOBs != null && StringUtils.isNotEmpty(testCaseWithBLOBs.getRequest())) {
|
if (testCaseWithBLOBs != null && StringUtils.isNotEmpty(testCaseWithBLOBs.getRequest())) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -91,6 +91,9 @@
|
||||||
<if test="reportRequest.projectId != null">
|
<if test="reportRequest.projectId != null">
|
||||||
AND project.id = #{reportRequest.projectId,jdbcType=VARCHAR}
|
AND project.id = #{reportRequest.projectId,jdbcType=VARCHAR}
|
||||||
</if>
|
</if>
|
||||||
|
<if test="reportRequest.testId != null">
|
||||||
|
AND ltr.test_id = #{reportRequest.testId,jdbcType=VARCHAR}
|
||||||
|
</if>
|
||||||
<if test="reportRequest.filters != null and reportRequest.filters.size() > 0">
|
<if test="reportRequest.filters != null and reportRequest.filters.size() > 0">
|
||||||
<foreach collection="reportRequest.filters.entrySet()" index="key" item="values">
|
<foreach collection="reportRequest.filters.entrySet()" index="key" item="values">
|
||||||
<if test="values != null and values.size() > 0">
|
<if test="values != null and values.size() > 0">
|
||||||
|
|
|
@ -274,7 +274,7 @@
|
||||||
#{value}
|
#{value}
|
||||||
</foreach>
|
</foreach>
|
||||||
</when>
|
</when>
|
||||||
<when test="key=='status'">
|
<when test="key=='reviewStatus'">
|
||||||
and test_case.review_status in
|
and test_case.review_status in
|
||||||
<foreach collection="values" item="value" separator="," open="(" close=")">
|
<foreach collection="values" item="value" separator="," open="(" close=")">
|
||||||
#{value}
|
#{value}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Map;
|
||||||
public class ReportRequest {
|
public class ReportRequest {
|
||||||
private String name;
|
private String name;
|
||||||
private String workspaceId;
|
private String workspaceId;
|
||||||
|
private String testId;
|
||||||
private String userId;
|
private String userId;
|
||||||
private List<OrderRequest> orders;
|
private List<OrderRequest> orders;
|
||||||
private Map<String, List<String>> filters;
|
private Map<String, List<String>> filters;
|
||||||
|
|
|
@ -1,21 +1,13 @@
|
||||||
package io.metersphere.track.service;
|
package io.metersphere.track.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.github.pagehelper.Page;
|
import com.github.pagehelper.Page;
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
|
import io.metersphere.api.dto.definition.ApiTestCaseDTO;
|
||||||
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
|
import io.metersphere.api.dto.definition.ApiTestCaseRequest;
|
||||||
import io.metersphere.api.dto.definition.RunDefinitionRequest;
|
|
||||||
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
|
import io.metersphere.api.dto.definition.TestPlanApiCaseDTO;
|
||||||
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.service.ApiDefinitionExecResultService;
|
import io.metersphere.api.service.ApiDefinitionExecResultService;
|
||||||
import io.metersphere.api.service.ApiDefinitionService;
|
import io.metersphere.api.service.ApiDefinitionService;
|
||||||
import io.metersphere.api.service.ApiTestCaseService;
|
import io.metersphere.api.service.ApiTestCaseService;
|
||||||
import io.metersphere.base.domain.ApiTestCaseExample;
|
|
||||||
import io.metersphere.base.domain.ApiTestCaseWithBLOBs;
|
|
||||||
import io.metersphere.base.domain.TestPlanApiCase;
|
import io.metersphere.base.domain.TestPlanApiCase;
|
||||||
import io.metersphere.base.domain.TestPlanApiCaseExample;
|
import io.metersphere.base.domain.TestPlanApiCaseExample;
|
||||||
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
|
import io.metersphere.base.mapper.TestPlanApiCaseMapper;
|
||||||
|
@ -25,15 +17,16 @@ import io.metersphere.commons.utils.Pager;
|
||||||
import io.metersphere.commons.utils.ServiceUtils;
|
import io.metersphere.commons.utils.ServiceUtils;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.track.request.testcase.TestPlanApiCaseBatchRequest;
|
import io.metersphere.track.request.testcase.TestPlanApiCaseBatchRequest;
|
||||||
import org.apache.jmeter.testelement.TestElement;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
@ -150,4 +143,11 @@ public class TestPlanApiCaseService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getState(String id) {
|
||||||
|
TestPlanApiCaseExample example = new TestPlanApiCaseExample();
|
||||||
|
example.createCriteria().andApiCaseIdEqualTo(id);
|
||||||
|
return testPlanApiCaseMapper.selectByExample(example).get(0).getStatus();
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -926,7 +926,7 @@
|
||||||
return bodyUploadFiles;
|
return bodyUploadFiles;
|
||||||
},
|
},
|
||||||
editScenario() {
|
editScenario() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve) => {
|
||||||
document.getElementById("inputDelay").focus(); // 保存前在input框自动失焦,以免保存失败
|
document.getElementById("inputDelay").focus(); // 保存前在input框自动失焦,以免保存失败
|
||||||
this.$refs['currentScenario'].validate((valid) => {
|
this.$refs['currentScenario'].validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
<template>
|
||||||
|
<ms-container>
|
||||||
|
<ms-main-container>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="24">
|
||||||
|
<overview-compare-card ref="overviewCard"/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="24">
|
||||||
|
<load-compare-card ref="loadCard"/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="24">
|
||||||
|
<response-time-compare-card ref="responseTimeCard"/>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</ms-main-container>
|
||||||
|
</ms-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MsContainer from "@/business/components/common/components/MsContainer";
|
||||||
|
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
|
||||||
|
import {checkoutTestManagerOrTestUser} from "@/common/js/utils";
|
||||||
|
import OverviewCompareCard from "@/business/components/performance/report/components/OverviewCompareCard";
|
||||||
|
import MsChart from "@/business/components/common/chart/MsChart";
|
||||||
|
import LoadCompareCard from "@/business/components/performance/report/components/LoadCompareCard";
|
||||||
|
import ResponseTimeCompareCard from "@/business/components/performance/report/components/ResponseTimeCompareCard";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "PerformanceReportCompare",
|
||||||
|
components: {ResponseTimeCompareCard, LoadCompareCard, MsChart, OverviewCompareCard, MsMainContainer, MsContainer},
|
||||||
|
mounted() {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isReadOnly() {
|
||||||
|
return !checkoutTestManagerOrTestUser();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
this.$refs.overviewCard.initTable();
|
||||||
|
this.$refs.loadCard.initCard();
|
||||||
|
this.$refs.responseTimeCard.initCard();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'$route'(to) {
|
||||||
|
if (to.name !== "ReportCompare") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.el-row {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -25,13 +25,12 @@
|
||||||
<el-button :disabled="isReadOnly" type="info" plain size="mini" @click="handleExport(reportName)">
|
<el-button :disabled="isReadOnly" type="info" plain size="mini" @click="handleExport(reportName)">
|
||||||
{{ $t('test_track.plan_view.export_report') }}
|
{{ $t('test_track.plan_view.export_report') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button :disabled="isReadOnly || report.status !== 'Completed'" type="default" plain size="mini" @click="compareReports()">
|
||||||
|
{{ $t('report.compare') }}
|
||||||
|
</el-button>
|
||||||
<el-button :disabled="isReadOnly" type="warning" plain size="mini" @click="downloadJtl()">
|
<el-button :disabled="isReadOnly" type="warning" plain size="mini" @click="downloadJtl()">
|
||||||
{{ $t('report.downloadJtl') }}
|
{{ $t('report.downloadJtl') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
<!--<el-button :disabled="isReadOnly" type="warning" plain size="mini">-->
|
|
||||||
<!--{{$t('report.compare')}}-->
|
|
||||||
<!--</el-button>-->
|
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
|
@ -83,6 +82,7 @@
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</ms-main-container>
|
</ms-main-container>
|
||||||
|
<same-test-reports ref="compareReports"/>
|
||||||
</ms-container>
|
</ms-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -99,11 +99,13 @@ import {checkoutTestManagerOrTestUser, exportPdf} from "@/common/js/utils";
|
||||||
import html2canvas from 'html2canvas';
|
import html2canvas from 'html2canvas';
|
||||||
import MsPerformanceReportExport from "./PerformanceReportExport";
|
import MsPerformanceReportExport from "./PerformanceReportExport";
|
||||||
import {Message} from "element-ui";
|
import {Message} from "element-ui";
|
||||||
|
import SameTestReports from "@/business/components/performance/report/components/SameTestReports";
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PerformanceReportView",
|
name: "PerformanceReportView",
|
||||||
components: {
|
components: {
|
||||||
|
SameTestReports,
|
||||||
MsPerformanceReportExport,
|
MsPerformanceReportExport,
|
||||||
MsReportErrorLog,
|
MsReportErrorLog,
|
||||||
MsReportLogDetails,
|
MsReportLogDetails,
|
||||||
|
@ -312,6 +314,9 @@ export default {
|
||||||
Message.error({message: JSON.parse(data).message || e.message, showClose: true});
|
Message.error({message: JSON.parse(data).message || e.message, showClose: true});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
compareReports() {
|
||||||
|
this.$refs.compareReports.open(this.report);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
@ -327,6 +332,8 @@ export default {
|
||||||
this.$set(this.report, "id", this.reportId);
|
this.$set(this.report, "id", this.reportId);
|
||||||
this.$set(this.report, "status", data.status);
|
this.$set(this.report, "status", data.status);
|
||||||
this.$set(this.report, "testId", data.testId);
|
this.$set(this.report, "testId", data.testId);
|
||||||
|
this.$set(this.report, "name", data.name);
|
||||||
|
this.$set(this.report, "createTime", data.createTime);
|
||||||
this.$set(this.report, "loadConfiguration", data.loadConfiguration);
|
this.$set(this.report, "loadConfiguration", data.loadConfiguration);
|
||||||
this.checkReportStatus(data.status);
|
this.checkReportStatus(data.status);
|
||||||
if (this.status === "Completed" || this.status === "Running") {
|
if (this.status === "Completed" || this.status === "Running") {
|
||||||
|
|
|
@ -25,37 +25,32 @@
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="name"
|
prop="name"
|
||||||
:label="$t('commons.name')"
|
:label="$t('commons.name')"
|
||||||
width="150"
|
|
||||||
show-overflow-tooltip>
|
show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="testName"
|
prop="testName"
|
||||||
:label="$t('report.test_name')"
|
:label="$t('report.test_name')"
|
||||||
width="150"
|
|
||||||
show-overflow-tooltip>
|
show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="projectName"
|
prop="projectName"
|
||||||
:label="$t('report.project_name')"
|
:label="$t('report.project_name')"
|
||||||
width="150"
|
|
||||||
show-overflow-tooltip>
|
show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="userName"
|
prop="userName"
|
||||||
:label="$t('report.user_name')"
|
:label="$t('report.user_name')"
|
||||||
width="150"
|
|
||||||
show-overflow-tooltip>
|
show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="createTime"
|
prop="createTime"
|
||||||
sortable
|
sortable
|
||||||
width="250"
|
|
||||||
:label="$t('commons.create_time')">
|
:label="$t('commons.create_time')">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="triggerMode" width="150" :label="'触发方式'" column-key="triggerMode"
|
<el-table-column prop="triggerMode" width="150" :label="$t('test_track.report.list.trigger_mode')" column-key="triggerMode"
|
||||||
:filters="triggerFilters">
|
:filters="triggerFilters">
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
|
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
|
||||||
|
@ -76,6 +71,8 @@
|
||||||
<template v-slot:default="scope">
|
<template v-slot:default="scope">
|
||||||
<ms-table-operator-button :tip="$t('api_report.detail')" icon="el-icon-s-data"
|
<ms-table-operator-button :tip="$t('api_report.detail')" icon="el-icon-s-data"
|
||||||
@exec="handleEdit(scope.row)" type="primary"/>
|
@exec="handleEdit(scope.row)" type="primary"/>
|
||||||
|
<ms-table-operator-button :tip="$t('load_test.report.diff')" icon="el-icon-s-operation"
|
||||||
|
@exec="handleDiff(scope.row)" type="warning"/>
|
||||||
<ms-table-operator-button :is-tester-permission="true" :tip="$t('api_report.delete')"
|
<ms-table-operator-button :is-tester-permission="true" :tip="$t('api_report.delete')"
|
||||||
icon="el-icon-delete" @exec="handleDelete(scope.row)" type="danger"/>
|
icon="el-icon-delete" @exec="handleDelete(scope.row)" type="danger"/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -85,6 +82,7 @@
|
||||||
:total="total"/>
|
:total="total"/>
|
||||||
</el-card>
|
</el-card>
|
||||||
</ms-main-container>
|
</ms-main-container>
|
||||||
|
<same-test-reports ref="compareReports"/>
|
||||||
</ms-container>
|
</ms-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -101,11 +99,14 @@ import MsTableHeader from "../../common/components/MsTableHeader";
|
||||||
import {LIST_CHANGE, PerformanceEvent} from "@/business/components/common/head/ListEvent";
|
import {LIST_CHANGE, PerformanceEvent} from "@/business/components/common/head/ListEvent";
|
||||||
import ShowMoreBtn from "../../track/case/components/ShowMoreBtn";
|
import ShowMoreBtn from "../../track/case/components/ShowMoreBtn";
|
||||||
import {_filter, _sort} from "@/common/js/tableUtils";
|
import {_filter, _sort} from "@/common/js/tableUtils";
|
||||||
|
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
|
||||||
|
import SameTestReports from "@/business/components/performance/report/components/SameTestReports";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PerformanceTestReportList",
|
name: "PerformanceTestReportList",
|
||||||
components: {
|
components: {
|
||||||
|
SameTestReports,
|
||||||
|
MsDialogFooter,
|
||||||
MsTableHeader,
|
MsTableHeader,
|
||||||
ReportTriggerModeItem,
|
ReportTriggerModeItem,
|
||||||
MsTableOperatorButton,
|
MsTableOperatorButton,
|
||||||
|
@ -200,6 +201,9 @@ export default {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
handleDiff(report) {
|
||||||
|
this.$refs.compareReports.open(report);
|
||||||
|
},
|
||||||
_handleDeleteNoMsg(report) {
|
_handleDeleteNoMsg(report) {
|
||||||
this.result = this.$post(this.deletePath + report.id, {}, () => {
|
this.result = this.$post(this.deletePath + report.id, {}, () => {
|
||||||
this.initTableData();
|
this.initTableData();
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
<template>
|
||||||
|
<el-card>
|
||||||
|
<template v-slot:header>
|
||||||
|
<span class="title">Load</span>
|
||||||
|
</template>
|
||||||
|
<div v-for="(option, index) in loadList" :key="index">
|
||||||
|
<ms-chart ref="chart1" :options="option" :autoresize="true"></ms-chart>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MsChart from "@/business/components/common/chart/MsChart";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "LoadCompareCard",
|
||||||
|
components: {MsChart},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loadList: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initCard() {
|
||||||
|
this.loadList = [];
|
||||||
|
this.reportId = this.$route.path.split('/')[4];
|
||||||
|
this.compareReports = JSON.parse(localStorage.getItem("compareReports"));
|
||||||
|
|
||||||
|
this.compareReports.forEach(report => {
|
||||||
|
this.initOverview(report);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
initOverview(report) {
|
||||||
|
this.$get("/performance/report/content/load_chart/" + report.id).then(res => {
|
||||||
|
let data = res.data.data;
|
||||||
|
let yAxisList = data.filter(m => m.yAxis2 === -1).map(m => m.yAxis);
|
||||||
|
let yAxis2List = data.filter(m => m.yAxis === -1).map(m => m.yAxis2);
|
||||||
|
let yAxisListMax = this._getChartMax(yAxisList);
|
||||||
|
let yAxis2ListMax = this._getChartMax(yAxis2List);
|
||||||
|
|
||||||
|
let yAxisIndex0List = data.filter(m => m.yAxis2 === -1).map(m => m.groupName);
|
||||||
|
yAxisIndex0List = this._unique(yAxisIndex0List);
|
||||||
|
let yAxisIndex1List = data.filter(m => m.yAxis === -1).map(m => m.groupName);
|
||||||
|
yAxisIndex1List = this._unique(yAxisIndex1List);
|
||||||
|
|
||||||
|
let loadOption = {
|
||||||
|
title: {
|
||||||
|
text: report.name + " " + this.$options.filters['timestampFormatDate'](report.createTime),
|
||||||
|
left: 'center',
|
||||||
|
top: 20,
|
||||||
|
textStyle: {
|
||||||
|
color: '#65A2FF'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
trigger: 'axis',
|
||||||
|
// extraCssText: 'z-index: 999;',
|
||||||
|
confine: true,
|
||||||
|
},
|
||||||
|
legend: {},
|
||||||
|
xAxis: {},
|
||||||
|
yAxis: [{
|
||||||
|
name: 'User',
|
||||||
|
type: 'value',
|
||||||
|
min: 0,
|
||||||
|
max: yAxisListMax,
|
||||||
|
splitNumber: 5,
|
||||||
|
interval: yAxisListMax / 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Transactions/s',
|
||||||
|
type: 'value',
|
||||||
|
splitNumber: 5,
|
||||||
|
min: 0,
|
||||||
|
max: yAxis2ListMax,
|
||||||
|
interval: yAxis2ListMax / 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: []
|
||||||
|
};
|
||||||
|
let setting = {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'users',
|
||||||
|
color: '#0CA74A',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'hits',
|
||||||
|
yAxisIndex: '1',
|
||||||
|
color: '#65A2FF',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'errors',
|
||||||
|
yAxisIndex: '1',
|
||||||
|
color: '#E6113C',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
yAxisIndex0List.forEach(item => {
|
||||||
|
setting["series"].splice(0, 0, {name: item, yAxisIndex: '0'})
|
||||||
|
})
|
||||||
|
|
||||||
|
yAxisIndex1List.forEach(item => {
|
||||||
|
setting["series"].splice(0, 0, {name: item, yAxisIndex: '1'})
|
||||||
|
})
|
||||||
|
this.loadList.push(this.generateOption(loadOption, data, setting));
|
||||||
|
}).catch(() => {
|
||||||
|
this.loadList = [];
|
||||||
|
})
|
||||||
|
},
|
||||||
|
generateOption(option, data, setting) {
|
||||||
|
let chartData = data;
|
||||||
|
let seriesArray = [];
|
||||||
|
for (let set in setting) {
|
||||||
|
if (set === "series") {
|
||||||
|
seriesArray = setting[set];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.$set(option, set, setting[set]);
|
||||||
|
}
|
||||||
|
let legend = [], series = {}, xAxis = [], seriesData = [];
|
||||||
|
chartData.forEach(item => {
|
||||||
|
if (!xAxis.includes(item.xAxis)) {
|
||||||
|
xAxis.push(item.xAxis);
|
||||||
|
}
|
||||||
|
xAxis.sort()
|
||||||
|
let name = item.groupName
|
||||||
|
if (!legend.includes(name)) {
|
||||||
|
legend.push(name)
|
||||||
|
series[name] = []
|
||||||
|
}
|
||||||
|
if (item.yAxis === -1) {
|
||||||
|
series[name].splice(xAxis.indexOf(item.xAxis), 0, [item.xAxis, item.yAxis2.toFixed(2)]);
|
||||||
|
} else {
|
||||||
|
series[name].splice(xAxis.indexOf(item.xAxis), 0, [item.xAxis, item.yAxis.toFixed(2)]);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$set(option.legend, "data", legend);
|
||||||
|
this.$set(option.legend, "type", "scroll");
|
||||||
|
this.$set(option.legend, "bottom", "10px");
|
||||||
|
this.$set(option.xAxis, "data", xAxis);
|
||||||
|
for (let name in series) {
|
||||||
|
let d = series[name];
|
||||||
|
d.sort((a, b) => a[0].localeCompare(b[0]));
|
||||||
|
let items = {
|
||||||
|
name: name,
|
||||||
|
type: 'line',
|
||||||
|
data: d,
|
||||||
|
smooth: true
|
||||||
|
};
|
||||||
|
let seriesArrayNames = seriesArray.map(m => m.name);
|
||||||
|
if (seriesArrayNames.includes(name)) {
|
||||||
|
for (let j = 0; j < seriesArray.length; j++) {
|
||||||
|
let seriesObj = seriesArray[j];
|
||||||
|
if (seriesObj['name'] === name) {
|
||||||
|
Object.assign(items, seriesObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seriesData.push(items);
|
||||||
|
}
|
||||||
|
this.$set(option, "series", seriesData);
|
||||||
|
return option;
|
||||||
|
},
|
||||||
|
_getChartMax(arr) {
|
||||||
|
const max = Math.max(...arr);
|
||||||
|
return Math.ceil(max / 4.5) * 5;
|
||||||
|
},
|
||||||
|
_unique(arr) {
|
||||||
|
return Array.from(new Set(arr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.echarts {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,67 @@
|
||||||
|
<template>
|
||||||
|
<el-card class="table-card">
|
||||||
|
<template v-slot:header>
|
||||||
|
<span class="title">Overview</span>
|
||||||
|
</template>
|
||||||
|
<el-table border :data="overviewList" class="adjust-table test-content">
|
||||||
|
<el-table-column prop="name" :label="$t('commons.name')"/>
|
||||||
|
<el-table-column prop="createTime" :label="$t('commons.create_time')">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="maxUsers" label="Max Users"/>
|
||||||
|
<el-table-column prop="avgTransactions" label="Avg.Transactions"/>
|
||||||
|
<el-table-column prop="errors" label="Errors"/>
|
||||||
|
<el-table-column prop="avgResponseTime" label="Avg.Response Time"/>
|
||||||
|
<el-table-column prop="responseTime90" label="90% Response Time"/>
|
||||||
|
<el-table-column prop="avgBandwidth" label="Avg.Bandwidth"/>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "OverviewCompareCard",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
reportId: null,
|
||||||
|
compareReports: [],
|
||||||
|
overviewList: [],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initTable() {
|
||||||
|
this.overviewList = [];
|
||||||
|
|
||||||
|
this.reportId = this.$route.path.split('/')[4];
|
||||||
|
this.compareReports = JSON.parse(localStorage.getItem("compareReports"));
|
||||||
|
|
||||||
|
this.compareReports.forEach(report => {
|
||||||
|
this.initOverview(report);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
initOverview(report) {
|
||||||
|
this.$get("/performance/report/content/testoverview/" + report.id).then(res => {
|
||||||
|
let data = res.data.data;
|
||||||
|
this.overviewList.push({
|
||||||
|
name: report.name,
|
||||||
|
createTime: report.createTime,
|
||||||
|
maxUsers: data.maxUsers,
|
||||||
|
avgThroughput: data.avgThroughput,
|
||||||
|
avgTransactions: data.avgTransactions,
|
||||||
|
errors: data.errors,
|
||||||
|
avgResponseTime: data.avgResponseTime,
|
||||||
|
responseTime90: data.responseTime90,
|
||||||
|
avgBandwidth: data.avgBandwidth,
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="ko"
|
prop="ko"
|
||||||
label="KO"
|
label="FAIL"
|
||||||
align="center"
|
align="center"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,188 @@
|
||||||
|
<template>
|
||||||
|
<el-card>
|
||||||
|
<template v-slot:header>
|
||||||
|
<span class="title">Response Time</span>
|
||||||
|
</template>
|
||||||
|
<div v-for="(option, index) in responseTimeList" :key="index">
|
||||||
|
<ms-chart ref="chart1" :options="option" :autoresize="true"></ms-chart>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MsChart from "@/business/components/common/chart/MsChart";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "ResponseTimeCompareCard",
|
||||||
|
components: {MsChart},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
responseTimeList: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
initCard() {
|
||||||
|
this.responseTimeList = [];
|
||||||
|
this.reportId = this.$route.path.split('/')[4];
|
||||||
|
this.compareReports = JSON.parse(localStorage.getItem("compareReports"));
|
||||||
|
|
||||||
|
this.compareReports.forEach(report => {
|
||||||
|
this.initOverview(report);
|
||||||
|
})
|
||||||
|
},
|
||||||
|
initOverview(report) {
|
||||||
|
this.$get("/performance/report/content/res_chart/" + report.id).then(res => {
|
||||||
|
let data = res.data.data;
|
||||||
|
let yAxisList = data.filter(m => m.yAxis2 === -1).map(m => m.yAxis);
|
||||||
|
let yAxis2List = data.filter(m => m.yAxis === -1).map(m => m.yAxis2);
|
||||||
|
let yAxisListMax = this._getChartMax(yAxisList);
|
||||||
|
let yAxis2ListMax = this._getChartMax(yAxis2List);
|
||||||
|
|
||||||
|
let yAxisIndex0List = data.filter(m => m.yAxis2 === -1).map(m => m.groupName);
|
||||||
|
yAxisIndex0List = this._unique(yAxisIndex0List);
|
||||||
|
let yAxisIndex1List = data.filter(m => m.yAxis === -1).map(m => m.groupName);
|
||||||
|
yAxisIndex1List = this._unique(yAxisIndex1List);
|
||||||
|
|
||||||
|
let resOption = {
|
||||||
|
title: {
|
||||||
|
text: report.name + " " + this.$options.filters['timestampFormatDate'](report.createTime),
|
||||||
|
left: 'center',
|
||||||
|
top: 20,
|
||||||
|
textStyle: {
|
||||||
|
color: '#99743C'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
trigger: 'axis',
|
||||||
|
// extraCssText: 'z-index: 999;',
|
||||||
|
confine: true,
|
||||||
|
formatter: function (params, ticket, callback) {
|
||||||
|
let result = "";
|
||||||
|
let name = params[0].name;
|
||||||
|
result += name + "<br/>";
|
||||||
|
for (let i = 0; i < params.length; i++) {
|
||||||
|
let seriesName = params[i].seriesName;
|
||||||
|
if (seriesName.length > 100) {
|
||||||
|
seriesName = seriesName.substring(0, 100);
|
||||||
|
}
|
||||||
|
let value = params[i].value;
|
||||||
|
let marker = params[i].marker;
|
||||||
|
result += marker + seriesName + ": " + value[1] + "<br/>";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {},
|
||||||
|
xAxis: {},
|
||||||
|
yAxis: [{
|
||||||
|
name: 'User',
|
||||||
|
type: 'value',
|
||||||
|
min: 0,
|
||||||
|
max: yAxisListMax,
|
||||||
|
interval: yAxisListMax / 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Response Time',
|
||||||
|
type: 'value',
|
||||||
|
min: 0,
|
||||||
|
max: yAxis2ListMax,
|
||||||
|
interval: yAxis2ListMax / 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: []
|
||||||
|
}
|
||||||
|
let setting = {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'users',
|
||||||
|
color: '#0CA74A',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
yAxisIndex0List.forEach(item => {
|
||||||
|
setting["series"].splice(0, 0, {name: item, yAxisIndex: '0'})
|
||||||
|
})
|
||||||
|
|
||||||
|
yAxisIndex1List.forEach(item => {
|
||||||
|
setting["series"].splice(0, 0, {name: item, yAxisIndex: '1'})
|
||||||
|
})
|
||||||
|
|
||||||
|
this.responseTimeList.push(this.generateOption(resOption, data, setting));
|
||||||
|
}).catch(() => {
|
||||||
|
this.responseTimeList = [];
|
||||||
|
})
|
||||||
|
},
|
||||||
|
generateOption(option, data, setting) {
|
||||||
|
let chartData = data;
|
||||||
|
let seriesArray = [];
|
||||||
|
for (let set in setting) {
|
||||||
|
if (set === "series") {
|
||||||
|
seriesArray = setting[set];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this.$set(option, set, setting[set]);
|
||||||
|
}
|
||||||
|
let legend = [], series = {}, xAxis = [], seriesData = [];
|
||||||
|
chartData.forEach(item => {
|
||||||
|
if (!xAxis.includes(item.xAxis)) {
|
||||||
|
xAxis.push(item.xAxis);
|
||||||
|
}
|
||||||
|
xAxis.sort()
|
||||||
|
let name = item.groupName
|
||||||
|
if (!legend.includes(name)) {
|
||||||
|
legend.push(name)
|
||||||
|
series[name] = []
|
||||||
|
}
|
||||||
|
if (item.yAxis === -1) {
|
||||||
|
series[name].splice(xAxis.indexOf(item.xAxis), 0, [item.xAxis, item.yAxis2.toFixed(2)]);
|
||||||
|
} else {
|
||||||
|
series[name].splice(xAxis.indexOf(item.xAxis), 0, [item.xAxis, item.yAxis.toFixed(2)]);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.$set(option.legend, "data", legend);
|
||||||
|
this.$set(option.legend, "type", "scroll");
|
||||||
|
this.$set(option.legend, "bottom", "10px");
|
||||||
|
this.$set(option.xAxis, "data", xAxis);
|
||||||
|
for (let name in series) {
|
||||||
|
let d = series[name];
|
||||||
|
d.sort((a, b) => a[0].localeCompare(b[0]));
|
||||||
|
let items = {
|
||||||
|
name: name,
|
||||||
|
type: 'line',
|
||||||
|
data: d,
|
||||||
|
smooth: true
|
||||||
|
};
|
||||||
|
let seriesArrayNames = seriesArray.map(m => m.name);
|
||||||
|
if (seriesArrayNames.includes(name)) {
|
||||||
|
for (let j = 0; j < seriesArray.length; j++) {
|
||||||
|
let seriesObj = seriesArray[j];
|
||||||
|
if (seriesObj['name'] === name) {
|
||||||
|
Object.assign(items, seriesObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seriesData.push(items);
|
||||||
|
}
|
||||||
|
this.$set(option, "series", seriesData);
|
||||||
|
return option;
|
||||||
|
},
|
||||||
|
_getChartMax(arr) {
|
||||||
|
const max = Math.max(...arr);
|
||||||
|
return Math.ceil(max / 4.5) * 5;
|
||||||
|
},
|
||||||
|
_unique(arr) {
|
||||||
|
return Array.from(new Set(arr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.echarts {
|
||||||
|
width: 100%;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,130 @@
|
||||||
|
<template>
|
||||||
|
<el-dialog :close-on-click-modal="false"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
:title="$t('已完成的测试报告')" width="60%"
|
||||||
|
:visible.sync="loadReportVisible">
|
||||||
|
<el-table v-loading="reportLoadingResult.loading"
|
||||||
|
class="basic-config"
|
||||||
|
:data="tableData"
|
||||||
|
@select-all="handleSelectAll"
|
||||||
|
@select="handleSelectionChange">
|
||||||
|
|
||||||
|
<el-table-column type="selection"/>
|
||||||
|
<el-table-column
|
||||||
|
prop="name"
|
||||||
|
:label="$t('commons.name')"
|
||||||
|
show-overflow-tooltip>
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<i v-if="scope.row.id === report.id" class="el-icon-star-on"></i> {{ scope.row.name }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="userName"
|
||||||
|
:label="$t('report.user_name')"
|
||||||
|
show-overflow-tooltip>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="triggerMode"
|
||||||
|
:label="$t('test_track.report.list.trigger_mode')">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<report-trigger-mode-item :trigger-mode="scope.row.triggerMode"/>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:label="$t('commons.create_time')">
|
||||||
|
<template v-slot:default="scope">
|
||||||
|
<i class="el-icon-time"/>
|
||||||
|
<span class="last-modified">{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<ms-table-pagination :change="getCompareReports" :current-page.sync="currentPage" :page-size.sync="pageSize"
|
||||||
|
:total="total"/>
|
||||||
|
|
||||||
|
<template v-slot:footer>
|
||||||
|
<ms-dialog-footer @cancel="close" @confirm="handleCompare"/>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
|
||||||
|
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
|
||||||
|
import ReportTriggerModeItem from "@/business/components/common/tableItem/ReportTriggerModeItem";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "SameTestReports",
|
||||||
|
components: {ReportTriggerModeItem, MsDialogFooter, MsTablePagination},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loadReportVisible: false,
|
||||||
|
reportLoadingResult: {},
|
||||||
|
tableData: [],
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
selectIds: new Set,
|
||||||
|
report: {},
|
||||||
|
compareReports: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open(report) {
|
||||||
|
this.report = report;
|
||||||
|
this.getCompareReports(report);
|
||||||
|
|
||||||
|
this.compareReports.push(report);
|
||||||
|
|
||||||
|
this.loadReportVisible = true;
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.loadReportVisible = false;
|
||||||
|
},
|
||||||
|
getCompareReports(report) {
|
||||||
|
|
||||||
|
let condition = {
|
||||||
|
testId: report.testId,
|
||||||
|
filters: {status: ["Completed"]}
|
||||||
|
};
|
||||||
|
this.reportLoadingResult = this.$post('/performance/report/list/all/' + this.currentPage + "/" + this.pageSize, condition, res => {
|
||||||
|
let data = res.data;
|
||||||
|
this.total = data.itemCount;
|
||||||
|
this.tableData = data.listObject;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleCompare() {
|
||||||
|
let reportIds = [...this.selectIds];
|
||||||
|
this.tableData
|
||||||
|
.filter(r => reportIds.indexOf(r.id) > -1 && this.report.id !== r.id)
|
||||||
|
.forEach(r => this.compareReports.push(r));
|
||||||
|
|
||||||
|
localStorage.setItem("compareReports", JSON.stringify(this.compareReports));
|
||||||
|
this.close();
|
||||||
|
this.$router.push({path: '/performance/report/compare/' + reportIds[0]});
|
||||||
|
},
|
||||||
|
handleSelectAll(selection) {
|
||||||
|
if (selection.length > 0) {
|
||||||
|
this.tableData.forEach(item => {
|
||||||
|
this.selectIds.add(item.id);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.tableData.forEach(item => {
|
||||||
|
if (this.selectIds.has(item.id)) {
|
||||||
|
this.selectIds.delete(item.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleSelectionChange(selection, row) {
|
||||||
|
if (this.selectIds.has(row.id)) {
|
||||||
|
this.selectIds.delete(row.id);
|
||||||
|
} else {
|
||||||
|
this.selectIds.add(row.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -1,5 +1,3 @@
|
||||||
import MsProject from "@/business/components/settings/project/MsProject";
|
|
||||||
|
|
||||||
const PerformanceTest = () => import('@/business/components/performance/PerformanceTest')
|
const PerformanceTest = () => import('@/business/components/performance/PerformanceTest')
|
||||||
const PerformanceTestHome = () => import('@/business/components/performance/home/PerformanceTestHome')
|
const PerformanceTestHome = () => import('@/business/components/performance/home/PerformanceTestHome')
|
||||||
const EditPerformanceTest = () => import('@/business/components/performance/test/EditPerformanceTest')
|
const EditPerformanceTest = () => import('@/business/components/performance/test/EditPerformanceTest')
|
||||||
|
@ -7,6 +5,7 @@ const PerformanceTestList = () => import('@/business/components/performance/test
|
||||||
const PerformanceTestReportList = () => import('@/business/components/performance/report/PerformanceTestReportList')
|
const PerformanceTestReportList = () => import('@/business/components/performance/report/PerformanceTestReportList')
|
||||||
const PerformanceChart = () => import('@/business/components/performance/report/components/PerformanceChart')
|
const PerformanceChart = () => import('@/business/components/performance/report/components/PerformanceChart')
|
||||||
const PerformanceReportView = () => import('@/business/components/performance/report/PerformanceReportView')
|
const PerformanceReportView = () => import('@/business/components/performance/report/PerformanceReportView')
|
||||||
|
const PerformanceReportCompare = () => import('@/business/components/performance/report/PerformanceReportCompare')
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
path: "/performance",
|
path: "/performance",
|
||||||
|
@ -62,6 +61,11 @@ export default {
|
||||||
path: "report/view/:reportId",
|
path: "report/view/:reportId",
|
||||||
name: "perReportView",
|
name: "perReportView",
|
||||||
component: PerformanceReportView
|
component: PerformanceReportView
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
path: "report/compare/:reportId",
|
||||||
|
name: "ReportCompare",
|
||||||
|
component: PerformanceReportCompare,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,6 +285,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
nodeChange(node, nodeIds, pNodes) {
|
nodeChange(node, nodeIds, pNodes) {
|
||||||
|
this.activeName = "default";
|
||||||
this.selectNodeIds = nodeIds;
|
this.selectNodeIds = nodeIds;
|
||||||
this.selectNode = node;
|
this.selectNode = node;
|
||||||
this.selectParentNodes = pNodes;
|
this.selectParentNodes = pNodes;
|
||||||
|
|
|
@ -303,20 +303,12 @@ export default {
|
||||||
},
|
},
|
||||||
created: function () {
|
created: function () {
|
||||||
this.$emit('setCondition', this.condition);
|
this.$emit('setCondition', this.condition);
|
||||||
if (this.trashEnable) {
|
this.condition.filters = {reviewStatus: ["Prepare", "Pass", "UnPass"]};
|
||||||
this.condition.filters = {status: ["Trash"]};
|
|
||||||
} else {
|
|
||||||
this.condition.filters = {status: ["Prepare", "Pass", "UnPass"]};
|
|
||||||
}
|
|
||||||
this.initTableData();
|
this.initTableData();
|
||||||
|
|
||||||
},
|
},
|
||||||
activated() {
|
activated() {
|
||||||
if (this.trashEnable) {
|
this.condition.filters = {reviewStatus: ["Prepare", "Pass", "UnPass"]};
|
||||||
this.condition.filters = {status: ["Trash"]};
|
|
||||||
} else {
|
|
||||||
this.condition.filters = {status: ["Prepare", "Pass", "UnPass"]};
|
|
||||||
}
|
|
||||||
this.initTableData();
|
this.initTableData();
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -372,15 +364,15 @@ export default {
|
||||||
case 'coverage':
|
case 'coverage':
|
||||||
this.condition.caseCoverage = 'coverage';
|
this.condition.caseCoverage = 'coverage';
|
||||||
break;
|
break;
|
||||||
/* case 'Prepare':
|
case 'Prepare':
|
||||||
this.condition.filters.status = [this.selectDataRange];
|
this.condition.filters.reviewStatus = [this.selectDataRange];
|
||||||
break;
|
break;
|
||||||
case 'Pass':
|
case 'Pass':
|
||||||
this.condition.filters.status = [this.selectDataRange];
|
this.condition.filters.reviewStatus = [this.selectDataRange];
|
||||||
break;
|
break;
|
||||||
case 'UnPass':
|
case 'UnPass':
|
||||||
this.condition.filters.status = [this.selectDataRange];
|
this.condition.filters.reviewStatus = [this.selectDataRange];
|
||||||
break;*/
|
break;
|
||||||
}
|
}
|
||||||
if (this.projectId) {
|
if (this.projectId) {
|
||||||
this.condition.projectId = this.projectId;
|
this.condition.projectId = this.projectId;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 07951ba17aef6f29e50cfd68e40de3266f9a60cd
|
Subproject commit 2115bd28a90854d2b6276a90878934715498c584
|
|
@ -541,7 +541,10 @@ export default {
|
||||||
threadgroup_at_least_one: 'At least one ThreadGroup is enabled',
|
threadgroup_at_least_one: 'At least one ThreadGroup is enabled',
|
||||||
load_api_automation_jmx: 'Import API automation scenario',
|
load_api_automation_jmx: 'Import API automation scenario',
|
||||||
project_file_exist: "The file already exists in the project, please import it directly",
|
project_file_exist: "The file already exists in the project, please import it directly",
|
||||||
project_file_update_type_error: 'Updated file types must be consistent'
|
project_file_update_type_error: 'Updated file types must be consistent',
|
||||||
|
report: {
|
||||||
|
diff: "Compare"
|
||||||
|
},
|
||||||
},
|
},
|
||||||
api_test: {
|
api_test: {
|
||||||
creator: "Creator",
|
creator: "Creator",
|
||||||
|
|
|
@ -438,7 +438,7 @@ export default {
|
||||||
export: '导出',
|
export: '导出',
|
||||||
export_to_ms_format: '导出 MeterSphere 格式',
|
export_to_ms_format: '导出 MeterSphere 格式',
|
||||||
export_to_swagger3_format: '导出 Swagger3.0 格式',
|
export_to_swagger3_format: '导出 Swagger3.0 格式',
|
||||||
compare: '比较',
|
compare: '报告对比',
|
||||||
generation_error: '报告生成错误, 无法查看, 请检查日志详情!',
|
generation_error: '报告生成错误, 无法查看, 请检查日志详情!',
|
||||||
being_generated: '报告正在生成中...',
|
being_generated: '报告正在生成中...',
|
||||||
delete_confirm: '确认删除报告: ',
|
delete_confirm: '确认删除报告: ',
|
||||||
|
@ -540,7 +540,10 @@ export default {
|
||||||
threadgroup_at_least_one: '至少启用一个线程组',
|
threadgroup_at_least_one: '至少启用一个线程组',
|
||||||
load_api_automation_jmx: '引用接口自动化场景',
|
load_api_automation_jmx: '引用接口自动化场景',
|
||||||
project_file_exist: "项目中已存在该文件,请直接引用",
|
project_file_exist: "项目中已存在该文件,请直接引用",
|
||||||
project_file_update_type_error: '更新的文件类型必须一致'
|
report: {
|
||||||
|
diff: "对比"
|
||||||
|
},
|
||||||
|
project_file_update_type_error: '更新的文件类型必须一致',
|
||||||
},
|
},
|
||||||
api_test: {
|
api_test: {
|
||||||
creator: "创建人",
|
creator: "创建人",
|
||||||
|
|
|
@ -438,7 +438,7 @@ export default {
|
||||||
export: '導出',
|
export: '導出',
|
||||||
export_to_ms_format: '導出 MeterSphere 格式',
|
export_to_ms_format: '導出 MeterSphere 格式',
|
||||||
export_to_swagger3_format: '導出 Swagger3.0 格式',
|
export_to_swagger3_format: '導出 Swagger3.0 格式',
|
||||||
compare: '比較',
|
compare: '報告比較',
|
||||||
generation_error: '報告生成錯誤, 無法查看, 請檢查日誌詳情!',
|
generation_error: '報告生成錯誤, 無法查看, 請檢查日誌詳情!',
|
||||||
being_generated: '報告正在生成中...',
|
being_generated: '報告正在生成中...',
|
||||||
delete_confirm: '確認刪除報告: ',
|
delete_confirm: '確認刪除報告: ',
|
||||||
|
@ -540,7 +540,10 @@ export default {
|
||||||
threadgroup_at_least_one: '至少啟用一個線程組',
|
threadgroup_at_least_one: '至少啟用一個線程組',
|
||||||
load_api_automation_jmx: '引用接口自動化場景',
|
load_api_automation_jmx: '引用接口自動化場景',
|
||||||
project_file_exist: "項目中已存在該文件,請直接引用",
|
project_file_exist: "項目中已存在該文件,請直接引用",
|
||||||
project_file_update_type_error: '更新的文件類型必須一致'
|
project_file_update_type_error: '更新的文件類型必須一致',
|
||||||
|
report: {
|
||||||
|
diff: "對比"
|
||||||
|
},
|
||||||
},
|
},
|
||||||
api_test: {
|
api_test: {
|
||||||
creator: "創建人",
|
creator: "創建人",
|
||||||
|
|
Loading…
Reference in New Issue