Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
b2d0e0cf3b
|
@ -8,12 +8,7 @@ import io.metersphere.commons.utils.PageUtils;
|
|||
import io.metersphere.commons.utils.Pager;
|
||||
import io.metersphere.controller.request.ReportRequest;
|
||||
import io.metersphere.dto.ReportDTO;
|
||||
import io.metersphere.report.base.ChartsData;
|
||||
import io.metersphere.report.base.Errors;
|
||||
import io.metersphere.report.base.ReportTimeInfo;
|
||||
import io.metersphere.report.base.TestOverview;
|
||||
import io.metersphere.report.dto.ErrorsTop5DTO;
|
||||
import io.metersphere.report.dto.RequestStatisticsDTO;
|
||||
import io.metersphere.report.base.*;
|
||||
import io.metersphere.service.ReportService;
|
||||
import io.metersphere.user.SessionUtils;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
|
@ -59,7 +54,7 @@ public class PerformanceReportController {
|
|||
}
|
||||
|
||||
@GetMapping("/content/{reportId}")
|
||||
public RequestStatisticsDTO getReportContent(@PathVariable String reportId) {
|
||||
public List<Statistics> getReportContent(@PathVariable String reportId) {
|
||||
return reportService.getReport(reportId);
|
||||
}
|
||||
|
||||
|
@ -69,7 +64,7 @@ public class PerformanceReportController {
|
|||
}
|
||||
|
||||
@GetMapping("/content/errors_top5/{reportId}")
|
||||
public ErrorsTop5DTO getReportErrorsTop5(@PathVariable String reportId) {
|
||||
public List<ErrorsTop5> getReportErrorsTop5(@PathVariable String reportId) {
|
||||
return reportService.getReportErrorsTOP5(reportId);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "performance")
|
||||
|
@ -88,6 +89,11 @@ public class PerformanceTestController {
|
|||
performanceTestService.run(request);
|
||||
}
|
||||
|
||||
@GetMapping("/log/{testId}")
|
||||
public Map<String, String> stop(@PathVariable String testId) {
|
||||
return performanceTestService.log(testId);
|
||||
}
|
||||
|
||||
@GetMapping("/file/metadata/{testId}")
|
||||
public List<FileMetadata> getFileMetadata(@PathVariable String testId) {
|
||||
return fileService.getFileMetadataByTestId(testId);
|
||||
|
|
|
@ -29,6 +29,11 @@ public class TestPlanTestCaseController {
|
|||
return PageUtils.setPageInfo(page, testPlanTestCaseService.getTestPlanCases(request));
|
||||
}
|
||||
|
||||
@PostMapping("/list/all")
|
||||
public List<TestPlanCaseDTO> getTestPlanCases(@RequestBody QueryTestPlanCaseRequest request){
|
||||
return testPlanTestCaseService.getTestPlanCases(request);
|
||||
}
|
||||
|
||||
@PostMapping("/edit")
|
||||
public void editTestCase(@RequestBody TestPlanTestCase testPlanTestCase){
|
||||
testPlanTestCaseService.editTestCase(testPlanTestCase);
|
||||
|
|
|
@ -10,7 +10,6 @@ import io.metersphere.dto.NodeDTO;
|
|||
import io.metersphere.engine.AbstractEngine;
|
||||
import io.metersphere.engine.EngineContext;
|
||||
import io.metersphere.engine.EngineFactory;
|
||||
import io.metersphere.engine.docker.request.BaseRequest;
|
||||
import io.metersphere.engine.docker.request.TestRequest;
|
||||
import io.metersphere.i18n.Translator;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
@ -91,14 +90,13 @@ public class DockerTestEngine extends AbstractEngine {
|
|||
public void stop() {
|
||||
// TODO 停止运行测试
|
||||
String testId = loadTest.getId();
|
||||
BaseRequest request = new BaseRequest();
|
||||
this.resourceList.forEach(r -> {
|
||||
NodeDTO node = JSON.parseObject(r.getConfiguration(), NodeDTO.class);
|
||||
String ip = node.getIp();
|
||||
Integer port = node.getPort();
|
||||
|
||||
String uri = String.format(BASE_URL + "/jmeter/container/stop/" + testId, ip, port);
|
||||
restTemplate.postForObject(uri, request, String.class);
|
||||
restTemplate.getForObject(uri, String.class);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -106,14 +104,13 @@ public class DockerTestEngine extends AbstractEngine {
|
|||
public Map<String, String> log() {
|
||||
String testId = loadTest.getId();
|
||||
Map<String, String> logs = new HashMap<>();
|
||||
BaseRequest request = new BaseRequest();
|
||||
this.resourceList.forEach(r -> {
|
||||
NodeDTO node = JSON.parseObject(r.getConfiguration(), NodeDTO.class);
|
||||
String ip = node.getIp();
|
||||
Integer port = node.getPort();
|
||||
|
||||
String uri = String.format(BASE_URL + "/jmeter/container/log/" + testId, ip, port);
|
||||
String log = restTemplate.postForObject(uri, request, String.class);
|
||||
String log = restTemplate.getForObject(uri, String.class);
|
||||
logs.put(node.getIp(), log);
|
||||
});
|
||||
return logs;
|
||||
|
|
|
@ -133,8 +133,10 @@ public class KubernetesTestEngine extends AbstractEngine {
|
|||
ClientCredential clientCredential = JSON.parseObject(configuration, ClientCredential.class);
|
||||
KubernetesProvider provider = new KubernetesProvider(JSON.toJSONString(clientCredential));
|
||||
provider.confirmNamespace(loadTest.getProjectId());
|
||||
String joblog = provider.getKubernetesClient().batch().jobs().inNamespace(loadTest.getProjectId()).withName("job-" + loadTest.getId()).getLog();
|
||||
logs.put(clientCredential.getMasterUrl(), joblog);
|
||||
try (KubernetesClient client = provider.getKubernetesClient()) {
|
||||
String joblog = client.batch().jobs().inNamespace(loadTest.getProjectId()).withName("job-" + loadTest.getId()).getLog();
|
||||
logs.put(clientCredential.getMasterUrl(), joblog);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
MSException.throwException(e);
|
||||
}
|
||||
|
|
|
@ -4,32 +4,26 @@ import com.opencsv.bean.CsvToBean;
|
|||
import com.opencsv.bean.CsvToBeanBuilder;
|
||||
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
|
||||
import io.metersphere.report.base.*;
|
||||
import io.metersphere.report.dto.ErrorsTop5DTO;
|
||||
import io.metersphere.report.dto.RequestStatisticsDTO;
|
||||
import io.metersphere.report.parse.ResultDataParse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.report.processor.ErrorsSummaryConsumer;
|
||||
import org.apache.jmeter.report.processor.StatisticsSummaryConsumer;
|
||||
import org.apache.jmeter.report.processor.Top5ErrorsBySamplerConsumer;
|
||||
import org.apache.jmeter.report.processor.graph.impl.ActiveThreadsGraphConsumer;
|
||||
import org.apache.jmeter.report.processor.graph.impl.HitsPerSecondGraphConsumer;
|
||||
import org.apache.jmeter.report.processor.graph.impl.ResponseTimeOverTimeGraphConsumer;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class GenerateReport {
|
||||
|
||||
private static final Integer ERRORS_TOP_SIZE = 5;
|
||||
private static final String DATE_TIME_PATTERN = "yyyy/MM/dd HH:mm:ss";
|
||||
private static final String TIME_PATTERN = "HH:mm:ss";
|
||||
|
||||
private static List<Metric> resolver(String jtlString) {
|
||||
HeaderColumnNameMappingStrategy<Metric> ms = new HeaderColumnNameMappingStrategy<>();
|
||||
ms.setType(Metric.class);
|
||||
|
@ -47,291 +41,54 @@ public class GenerateReport {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static RequestStatisticsDTO getRequestStatistics(String jtlString) {
|
||||
List<Integer> allElapseTimeList = new ArrayList<>();
|
||||
List<RequestStatistics> requestStatisticsList = new ArrayList<>();
|
||||
DecimalFormat decimalFormat = new DecimalFormat("0.00");
|
||||
|
||||
List<Metric> totalMetricList = resolver(jtlString);
|
||||
Map<String, List<Metric>> jtlLabelMap = totalMetricList.stream().collect(Collectors.groupingBy(Metric::getLabel));
|
||||
Iterator<Map.Entry<String, List<Metric>>> iterator = jtlLabelMap.entrySet().iterator();
|
||||
|
||||
int totalElapsedTime = 0;
|
||||
float totalBytes = 0f;
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, List<Metric>> entry = iterator.next();
|
||||
String label = entry.getKey();
|
||||
List<Metric> metricList = entry.getValue();
|
||||
List<Integer> elapsedList = new ArrayList<>();
|
||||
|
||||
int jtlSamplesSize = 0, oneLineElapsedTime = 0, failSize = 0;
|
||||
float oneLineBytes = 0f;
|
||||
|
||||
for (int i = 0; i < metricList.size(); i++) {
|
||||
try {
|
||||
Metric row = metricList.get(i);
|
||||
String elapsed = row.getElapsed();
|
||||
oneLineElapsedTime += Integer.parseInt(elapsed);
|
||||
totalElapsedTime += Integer.parseInt(elapsed);
|
||||
elapsedList.add(Integer.valueOf(elapsed));
|
||||
allElapseTimeList.add(Integer.valueOf(elapsed));
|
||||
|
||||
String isSuccess = row.getSuccess();
|
||||
if (!"true".equals(isSuccess)) {
|
||||
failSize++;
|
||||
}
|
||||
String bytes = row.getBytes();
|
||||
oneLineBytes += Float.parseFloat(bytes);
|
||||
totalBytes += Float.parseFloat(bytes);
|
||||
jtlSamplesSize++;
|
||||
} catch (Exception e) {
|
||||
System.out.println("exception i:" + i);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(elapsedList);
|
||||
|
||||
int tp90 = elapsedList.size() * 90 / 100;
|
||||
int tp95 = elapsedList.size() * 95 / 100;
|
||||
int tp99 = elapsedList.size() * 99 / 100;
|
||||
|
||||
metricList.sort(Comparator.comparing(t0 -> Long.valueOf(t0.getTimestamp())));
|
||||
long time = Long.parseLong(metricList.get(metricList.size() - 1).getTimestamp()) - Long.parseLong(metricList.get(0).getTimestamp())
|
||||
+ Long.parseLong(metricList.get(metricList.size() - 1).getElapsed());
|
||||
|
||||
RequestStatistics requestStatistics = new RequestStatistics();
|
||||
requestStatistics.setRequestLabel(label);
|
||||
requestStatistics.setSamples(jtlSamplesSize);
|
||||
|
||||
String average = decimalFormat.format((float) oneLineElapsedTime / jtlSamplesSize);
|
||||
requestStatistics.setAverage(average);
|
||||
|
||||
/*
|
||||
* TP90的计算
|
||||
* 1,把一段时间内全部的请求的响应时间,从小到大排序,获得序列A
|
||||
* 2,总的请求数量,乘以90%,获得90%对应的请求个数C
|
||||
* 3,从序列A中找到第C个请求,它的响应时间,即为TP90的值
|
||||
* 其余相似的指标还有TP95, TP99
|
||||
*/
|
||||
// todo tp90
|
||||
requestStatistics.setTp90(elapsedList.get(tp90) + "");
|
||||
requestStatistics.setTp95(elapsedList.get(tp95) + "");
|
||||
requestStatistics.setTp99(elapsedList.get(tp99) + "");
|
||||
|
||||
double avgHits = (double) metricList.size() / (time * 1.0 / 1000);
|
||||
requestStatistics.setAvgHits(decimalFormat.format(avgHits));
|
||||
|
||||
requestStatistics.setMin(elapsedList.get(0) + "");
|
||||
requestStatistics.setMax(elapsedList.get(jtlSamplesSize - 1) + "");
|
||||
requestStatistics.setErrors(decimalFormat.format(failSize * 100.0 / jtlSamplesSize) + "%");
|
||||
requestStatistics.setKo(failSize);
|
||||
/*
|
||||
* 所有的相同请求的bytes总和 / 1024 / 请求持续运行的时间=sum(bytes)/1024/total time
|
||||
* total time = 最大时间戳 - 最小时间戳 + 最后请求的响应时间
|
||||
*/
|
||||
requestStatistics.setKbPerSec(decimalFormat.format(oneLineBytes * 1.0 / 1024 / (time * 1.0 / 1000)));
|
||||
requestStatisticsList.add(requestStatistics);
|
||||
}
|
||||
|
||||
Collections.sort(allElapseTimeList);
|
||||
int totalTP90 = allElapseTimeList.size() * 90 / 100;
|
||||
int totalTP95 = allElapseTimeList.size() * 95 / 100;
|
||||
int totalTP99 = allElapseTimeList.size() * 99 / 100;
|
||||
|
||||
Integer min = allElapseTimeList.get(0);
|
||||
Integer max = allElapseTimeList.get(allElapseTimeList.size() - 1);
|
||||
|
||||
int allSamples = requestStatisticsList.stream().mapToInt(RequestStatistics::getSamples).sum();
|
||||
int failSize = requestStatisticsList.stream().mapToInt(RequestStatistics::getKo).sum();
|
||||
|
||||
double errors = (double) failSize / allSamples * 100;
|
||||
String totalErrors = decimalFormat.format(errors);
|
||||
double average = (double) totalElapsedTime / allSamples;
|
||||
String totalAverage = decimalFormat.format(average);
|
||||
|
||||
RequestStatisticsDTO statisticsDTO = new RequestStatisticsDTO();
|
||||
statisticsDTO.setRequestStatisticsList(requestStatisticsList);
|
||||
statisticsDTO.setTotalLabel("Total");
|
||||
statisticsDTO.setTotalSamples(String.valueOf(allSamples));
|
||||
statisticsDTO.setTotalErrors(totalErrors + "%");
|
||||
statisticsDTO.setTotalAverage(totalAverage);
|
||||
statisticsDTO.setTotalMin(String.valueOf(min));
|
||||
statisticsDTO.setTotalMax(String.valueOf(max));
|
||||
statisticsDTO.setTotalTP90(String.valueOf(allElapseTimeList.get(totalTP90)));
|
||||
statisticsDTO.setTotalTP95(String.valueOf(allElapseTimeList.get(totalTP95)));
|
||||
statisticsDTO.setTotalTP99(String.valueOf(allElapseTimeList.get(totalTP99)));
|
||||
|
||||
totalMetricList.sort(Comparator.comparing(t0 -> Long.valueOf(t0.getTimestamp())));
|
||||
|
||||
long ms = Long.parseLong(totalMetricList.get(totalMetricList.size() - 1).getTimestamp()) - Long.parseLong(totalMetricList.get(0).getTimestamp())
|
||||
+ Long.parseLong(totalMetricList.get(totalMetricList.size() - 1).getElapsed());
|
||||
double avgThroughput = (double) totalMetricList.size() / (ms * 1.0 / 1000);
|
||||
|
||||
statisticsDTO.setTotalAvgHits(decimalFormat.format(avgThroughput));
|
||||
statisticsDTO.setTotalAvgBandwidth(decimalFormat.format(totalBytes * 1.0 / 1024 / (ms * 1.0 / 1000)));
|
||||
|
||||
return statisticsDTO;
|
||||
}
|
||||
|
||||
public static List<Errors> getErrorsList(String jtlString) {
|
||||
List<Metric> totalMetricList = resolver(jtlString);
|
||||
List<Errors> errorsList = new ArrayList<>();
|
||||
DecimalFormat decimalFormat = new DecimalFormat("0.00");
|
||||
|
||||
List<Metric> falseList = new ArrayList<>();
|
||||
for (Metric metric : totalMetricList) {
|
||||
if (StringUtils.equals("false", metric.getSuccess())) {
|
||||
falseList.add(metric);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, List<Metric>> jtlMap = falseList.stream().collect(Collectors.groupingBy(GenerateReport::getResponseCodeAndFailureMessage));
|
||||
|
||||
for (Map.Entry<String, List<Metric>> next : jtlMap.entrySet()) {
|
||||
String key = next.getKey();
|
||||
List<Metric> metricList = next.getValue();
|
||||
Errors errors = new Errors();
|
||||
errors.setErrorType(key);
|
||||
errors.setErrorNumber(String.valueOf(metricList.size()));
|
||||
int errorSize = metricList.size();
|
||||
int errorAllSize = falseList.size();
|
||||
int allSamples = totalMetricList.size();
|
||||
errors.setPrecentOfErrors(decimalFormat.format((double) errorSize / errorAllSize * 100) + "%");
|
||||
errors.setPrecentOfAllSamples(decimalFormat.format((double) errorSize / allSamples * 100) + "%");
|
||||
errorsList.add(errors);
|
||||
}
|
||||
|
||||
return errorsList;
|
||||
Map<String, Object> statisticsDataMap = ResultDataParse.getSummryDataMap(jtlString, new ErrorsSummaryConsumer());
|
||||
return ResultDataParse.summaryMapParsing(statisticsDataMap, Errors.class);
|
||||
}
|
||||
|
||||
private static String getResponseCodeAndFailureMessage(Metric metric) {
|
||||
return metric.getResponseCode() + "/" + metric.getResponseMessage();
|
||||
public static List<ErrorsTop5> getErrorsTop5List(String jtlString) {
|
||||
Map<String, Object> statisticsDataMap = ResultDataParse.getSummryDataMap(jtlString, new Top5ErrorsBySamplerConsumer());
|
||||
return ResultDataParse.summaryMapParsing(statisticsDataMap, ErrorsTop5.class);
|
||||
}
|
||||
|
||||
public static ErrorsTop5DTO getErrorsTop5DTO(String jtlString) {
|
||||
List<Metric> totalMetricList = resolver(jtlString);
|
||||
ErrorsTop5DTO top5DTO = new ErrorsTop5DTO();
|
||||
List<ErrorsTop5> errorsTop5s = new ArrayList<>();
|
||||
|
||||
List<Metric> falseList = Objects.requireNonNull(totalMetricList).stream()
|
||||
.filter(metric -> StringUtils.equals("false", metric.getSuccess()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<String, List<Metric>> collect = falseList.stream()
|
||||
.collect(Collectors.groupingBy(GenerateReport::getResponseCodeAndFailureMessage));
|
||||
|
||||
for (Map.Entry<String, List<Metric>> next : collect.entrySet()) {
|
||||
String key = next.getKey();
|
||||
List<Metric> metricList = next.getValue();
|
||||
List<Metric> list = new ArrayList<>();
|
||||
for (Metric metric : totalMetricList) {
|
||||
if (StringUtils.equals(metric.getLabel(), metricList.get(0).getLabel())) {
|
||||
list.add(metric);
|
||||
}
|
||||
}
|
||||
|
||||
ErrorsTop5 errorsTop5 = new ErrorsTop5();
|
||||
errorsTop5.setSamples(String.valueOf(list.size()));
|
||||
errorsTop5.setSample(metricList.get(0).getLabel());
|
||||
errorsTop5.setErrors(String.valueOf(metricList.size()));
|
||||
errorsTop5.setErrorsAllSize(metricList.size());
|
||||
errorsTop5.setError(key);
|
||||
errorsTop5s.add(errorsTop5);
|
||||
}
|
||||
|
||||
errorsTop5s.sort((t0, t1) -> t1.getErrorsAllSize().compareTo(t0.getErrorsAllSize()));
|
||||
|
||||
if (errorsTop5s.size() >= ERRORS_TOP_SIZE) {
|
||||
errorsTop5s = errorsTop5s.subList(0, ERRORS_TOP_SIZE);
|
||||
}
|
||||
|
||||
top5DTO.setLabel("Total");
|
||||
top5DTO.setErrorsTop5List(errorsTop5s);
|
||||
top5DTO.setTotalSamples(String.valueOf(totalMetricList.size()));
|
||||
top5DTO.setTotalErrors(String.valueOf(falseList.size()));
|
||||
int size = errorsTop5s.size();
|
||||
// Total行 信息
|
||||
top5DTO.setError1(size > 0 ? errorsTop5s.get(0).getError() : null);
|
||||
top5DTO.setError1Size(size > 0 ? errorsTop5s.get(0).getErrors() : null);
|
||||
top5DTO.setError2(size > 1 ? errorsTop5s.get(1).getError() : null);
|
||||
top5DTO.setError2Size(size > 1 ? errorsTop5s.get(1).getErrors() : null);
|
||||
top5DTO.setError3(size > 2 ? errorsTop5s.get(2).getError() : null);
|
||||
top5DTO.setError3Size(size > 2 ? errorsTop5s.get(2).getErrors() : null);
|
||||
top5DTO.setError4(size > 3 ? errorsTop5s.get(3).getError() : null);
|
||||
top5DTO.setError4Size(size > 3 ? errorsTop5s.get(3).getErrors() : null);
|
||||
top5DTO.setError5(size > 4 ? errorsTop5s.get(4).getError() : null);
|
||||
top5DTO.setError5Size(size > 4 ? errorsTop5s.get(4).getErrors() : null);
|
||||
|
||||
return top5DTO;
|
||||
public static List<Statistics> getRequestStatistics(String jtlString) {
|
||||
Map<String, Object> statisticsDataMap = ResultDataParse.getSummryDataMap(jtlString, new StatisticsSummaryConsumer());
|
||||
return ResultDataParse.summaryMapParsing(statisticsDataMap, Statistics.class);
|
||||
}
|
||||
|
||||
public static TestOverview getTestOverview(String jtlString) {
|
||||
TestOverview testOverview = new TestOverview();
|
||||
DecimalFormat decimalFormat = new DecimalFormat("0.00");
|
||||
|
||||
List<Metric> totalLineList = GenerateReport.resolver(jtlString);
|
||||
// todo 修改测试概览的数值
|
||||
List<Metric> totalLineList2 = GenerateReport.resolver(jtlString);
|
||||
// 时间戳转时间
|
||||
for (Metric metric : totalLineList2) {
|
||||
metric.setTimestamp(stampToDate(DATE_TIME_PATTERN, metric.getTimestamp()));
|
||||
}
|
||||
Map<String, Object> activeDataMap = ResultDataParse.getGraphDataMap(jtlString, new ActiveThreadsGraphConsumer());
|
||||
List<ChartsData> usersList = ResultDataParse.graphMapParsing(activeDataMap, "users");
|
||||
Optional<ChartsData> max = usersList.stream().max(Comparator.comparing(ChartsData::getyAxis));
|
||||
int maxUser = max.get().getyAxis().setScale(0, BigDecimal.ROUND_UP).intValue();
|
||||
|
||||
Map<String, List<Metric>> collect2 = Objects.requireNonNull(totalLineList2).stream().collect(Collectors.groupingBy(Metric::getTimestamp));
|
||||
List<Map.Entry<String, List<Metric>>> entries = new ArrayList<>(collect2.entrySet());
|
||||
int maxUsers = 0;
|
||||
for (Map.Entry<String, List<Metric>> entry : entries) {
|
||||
List<Metric> metrics = entry.getValue();
|
||||
Map<String, List<Metric>> metricsMap = metrics.stream().collect(Collectors.groupingBy(Metric::getThreadName));
|
||||
if (metricsMap.size() > maxUsers) {
|
||||
maxUsers = metricsMap.size();
|
||||
}
|
||||
}
|
||||
Map<String, Object> hitsDataMap = ResultDataParse.getGraphDataMap(jtlString, new HitsPerSecondGraphConsumer());
|
||||
List<ChartsData> hitsList = ResultDataParse.graphMapParsing(hitsDataMap, "hits");
|
||||
double hits = hitsList.stream().map(ChartsData::getyAxis)
|
||||
.mapToDouble(BigDecimal::doubleValue)
|
||||
.average().orElse(0);
|
||||
|
||||
Map<String, List<Metric>> collect = totalLineList.stream().collect(Collectors.groupingBy(Metric::getTimestamp));
|
||||
Iterator<Map.Entry<String, List<Metric>>> iterator = collect.entrySet().iterator();
|
||||
Map<String, Object> errorDataMap = ResultDataParse.getSummryDataMap(jtlString, new StatisticsSummaryConsumer());
|
||||
List<Statistics> statisticsList = ResultDataParse.summaryMapParsing(errorDataMap, Statistics.class);
|
||||
Optional<Double> error = statisticsList.stream().map(item -> Double.parseDouble(item.getError())).reduce(Double::sum);
|
||||
|
||||
int totalElapsed = 0;
|
||||
float totalBytes = 0f;
|
||||
Map<String, Object> responseDataMap = ResultDataParse.getGraphDataMap(jtlString, new ResponseTimeOverTimeGraphConsumer());
|
||||
List<ChartsData> responseDataList = ResultDataParse.graphMapParsing(responseDataMap, "response");
|
||||
double responseTime = responseDataList.stream().map(ChartsData::getyAxis)
|
||||
.mapToDouble(BigDecimal::doubleValue)
|
||||
.average().orElse(0);
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, List<Metric>> entry = iterator.next();
|
||||
List<Metric> metricList = entry.getValue();
|
||||
|
||||
for (Metric metric : metricList) {
|
||||
String elapsed = metric.getElapsed();
|
||||
totalElapsed += Integer.parseInt(elapsed);
|
||||
String bytes = metric.getBytes();
|
||||
totalBytes += Float.parseFloat(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
totalLineList.sort(Comparator.comparing(t0 -> Long.valueOf(t0.getTimestamp())));
|
||||
|
||||
testOverview.setMaxUsers(String.valueOf(maxUsers));
|
||||
|
||||
List<Metric> list90 = totalLineList.subList(0, totalLineList.size() * 9 / 10);
|
||||
long sum = list90.stream().mapToLong(metric -> Long.parseLong(metric.getElapsed())).sum();
|
||||
double avg90 = (double) sum / 1000 / list90.size();
|
||||
testOverview.setResponseTime90(decimalFormat.format(avg90));
|
||||
|
||||
long timesStampStart = Long.parseLong(totalLineList.get(0).getTimestamp());
|
||||
long timesStampEnd = Long.parseLong(totalLineList.get(totalLineList.size() - 1).getTimestamp());
|
||||
long time = timesStampEnd - timesStampStart + Long.parseLong(totalLineList.get(totalLineList.size() - 1).getElapsed());
|
||||
double avgThroughput = (double) totalLineList.size() / (time * 1.0 / 1000);
|
||||
testOverview.setAvgThroughput(decimalFormat.format(avgThroughput));
|
||||
|
||||
List<Metric> falseList = totalLineList.stream().filter(metric -> StringUtils.equals("false", metric.getSuccess())).collect(Collectors.toList());
|
||||
double errors = falseList.size() * 1.0 / totalLineList.size() * 100;
|
||||
testOverview.setErrors(decimalFormat.format(errors));
|
||||
|
||||
double avg = totalElapsed * 1.0 / totalLineList.size() / 1000;
|
||||
testOverview.setAvgResponseTime(decimalFormat.format(avg));
|
||||
|
||||
double bandwidth = totalBytes * 1.0 / time;
|
||||
testOverview.setAvgBandwidth(decimalFormat.format(bandwidth));
|
||||
TestOverview testOverview = new TestOverview();
|
||||
testOverview.setMaxUsers(String.valueOf(maxUser));
|
||||
testOverview.setAvgThroughput(decimalFormat.format(hits));
|
||||
testOverview.setErrors(decimalFormat.format(error.get()));
|
||||
testOverview.setAvgResponseTime(decimalFormat.format(responseTime / 1000));
|
||||
|
||||
// todo
|
||||
testOverview.setResponseTime90("0");
|
||||
testOverview.setAvgBandwidth("0");
|
||||
return testOverview;
|
||||
}
|
||||
|
||||
|
@ -354,7 +111,6 @@ public class GenerateReport {
|
|||
}
|
||||
|
||||
public static ReportTimeInfo getReportTimeInfo(String jtlString) {
|
||||
ReportTimeInfo reportTimeInfo = new ReportTimeInfo();
|
||||
List<Metric> totalLineList = GenerateReport.resolver(jtlString);
|
||||
|
||||
totalLineList.sort(Comparator.comparing(t0 -> Long.valueOf(t0.getTimestamp())));
|
||||
|
@ -365,35 +121,15 @@ public class GenerateReport {
|
|||
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
|
||||
String startTime = dtf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(startTimeStamp)), ZoneId.systemDefault()));
|
||||
String endTime = dtf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(endTimeStamp)), ZoneId.systemDefault()));
|
||||
reportTimeInfo.setStartTime(startTime);
|
||||
reportTimeInfo.setEndTime(endTime);
|
||||
|
||||
Date startDate = new Date(Long.parseLong(startTimeStamp));
|
||||
Date endDate = new Date(Long.parseLong(endTimeStamp));
|
||||
long timestamp = endDate.getTime() - startDate.getTime();
|
||||
reportTimeInfo.setDuration(String.valueOf(timestamp * 1.0 / 1000 / 60));
|
||||
|
||||
// todo 时间问题
|
||||
long seconds = Duration.between(Instant.ofEpochMilli(Long.parseLong(startTimeStamp)), Instant.ofEpochMilli(Long.parseLong(endTimeStamp))).getSeconds();
|
||||
ReportTimeInfo reportTimeInfo = new ReportTimeInfo();
|
||||
reportTimeInfo.setStartTime(startTime);
|
||||
reportTimeInfo.setEndTime(endTime);
|
||||
reportTimeInfo.setDuration(String.valueOf(seconds));
|
||||
|
||||
return reportTimeInfo;
|
||||
}
|
||||
|
||||
private static String stampToDate(String pattern, String timeStamp) {
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
|
||||
LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(timeStamp)), ZoneId.systemDefault());
|
||||
return localDateTime.format(dateTimeFormatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param "yyyy-MM-dd HH:mm:ss"
|
||||
* @return "HH:mm:ss"
|
||||
*/
|
||||
private static String formatDate(String dateString) throws ParseException {
|
||||
SimpleDateFormat before = new SimpleDateFormat(DATE_TIME_PATTERN);
|
||||
SimpleDateFormat after = new SimpleDateFormat(TIME_PATTERN);
|
||||
return after.format(before.parse(dateString));
|
||||
}
|
||||
|
||||
}
|
|
@ -4,9 +4,17 @@ public class ErrorsTop5 {
|
|||
|
||||
private String sample;
|
||||
private String samples;
|
||||
private Integer errorsAllSize;
|
||||
private String error;
|
||||
private String errors;
|
||||
private String errorsAllSize;
|
||||
private String error1;
|
||||
private String error1Size;
|
||||
private String error2;
|
||||
private String error2Size;
|
||||
private String error3;
|
||||
private String error3Size;
|
||||
private String error4;
|
||||
private String error4Size;
|
||||
private String error5;
|
||||
private String error5Size;
|
||||
|
||||
public String getSample() {
|
||||
return sample;
|
||||
|
@ -24,27 +32,91 @@ public class ErrorsTop5 {
|
|||
this.samples = samples;
|
||||
}
|
||||
|
||||
public Integer getErrorsAllSize() {
|
||||
public String getErrorsAllSize() {
|
||||
return errorsAllSize;
|
||||
}
|
||||
|
||||
public void setErrorsAllSize(Integer errorsAllSize) {
|
||||
public void setErrorsAllSize(String errorsAllSize) {
|
||||
this.errorsAllSize = errorsAllSize;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
public String getError1() {
|
||||
return error1;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
public void setError1(String error1) {
|
||||
this.error1 = error1;
|
||||
}
|
||||
|
||||
public String getErrors() {
|
||||
return errors;
|
||||
public String getError1Size() {
|
||||
return error1Size;
|
||||
}
|
||||
|
||||
public void setErrors(String errors) {
|
||||
this.errors = errors;
|
||||
public void setError1Size(String error1Size) {
|
||||
this.error1Size = error1Size;
|
||||
}
|
||||
|
||||
public String getError2() {
|
||||
return error2;
|
||||
}
|
||||
|
||||
public void setError2(String error2) {
|
||||
this.error2 = error2;
|
||||
}
|
||||
|
||||
public String getError2Size() {
|
||||
return error2Size;
|
||||
}
|
||||
|
||||
public void setError2Size(String error2Size) {
|
||||
this.error2Size = error2Size;
|
||||
}
|
||||
|
||||
public String getError3() {
|
||||
return error3;
|
||||
}
|
||||
|
||||
public void setError3(String error3) {
|
||||
this.error3 = error3;
|
||||
}
|
||||
|
||||
public String getError3Size() {
|
||||
return error3Size;
|
||||
}
|
||||
|
||||
public void setError3Size(String error3Size) {
|
||||
this.error3Size = error3Size;
|
||||
}
|
||||
|
||||
public String getError4() {
|
||||
return error4;
|
||||
}
|
||||
|
||||
public void setError4(String error4) {
|
||||
this.error4 = error4;
|
||||
}
|
||||
|
||||
public String getError4Size() {
|
||||
return error4Size;
|
||||
}
|
||||
|
||||
public void setError4Size(String error4Size) {
|
||||
this.error4Size = error4Size;
|
||||
}
|
||||
|
||||
public String getError5() {
|
||||
return error5;
|
||||
}
|
||||
|
||||
public void setError5(String error5) {
|
||||
this.error5 = error5;
|
||||
}
|
||||
|
||||
public String getError5Size() {
|
||||
return error5Size;
|
||||
}
|
||||
|
||||
public void setError5Size(String error5Size) {
|
||||
this.error5Size = error5Size;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,136 +0,0 @@
|
|||
package io.metersphere.report.base;
|
||||
|
||||
public class RequestStatistics {
|
||||
|
||||
/**请求标签*/
|
||||
private String requestLabel;
|
||||
|
||||
/**压测请求数*/
|
||||
private Integer samples;
|
||||
|
||||
/**平均响应时间*/
|
||||
private String average;
|
||||
|
||||
/**平均点击率*/
|
||||
private String avgHits;
|
||||
|
||||
/**90% Line*/
|
||||
private String tp90;
|
||||
|
||||
/**95% Line*/
|
||||
private String tp95;
|
||||
|
||||
/**99% Line*/
|
||||
private String tp99;
|
||||
|
||||
/**最小请求时间 Min Response Time /ms */
|
||||
private String min;
|
||||
|
||||
/**最大请求时间 Max Response Time /ms */
|
||||
private String max;
|
||||
|
||||
/**吞吐量 KB/sec*/
|
||||
private String kbPerSec;
|
||||
|
||||
/**错误率 Error Percentage */
|
||||
private String errors;
|
||||
|
||||
/**错误个数*/
|
||||
private Integer ko;
|
||||
|
||||
public String getRequestLabel() {
|
||||
return requestLabel;
|
||||
}
|
||||
|
||||
public void setRequestLabel(String requestLabel) {
|
||||
this.requestLabel = requestLabel;
|
||||
}
|
||||
|
||||
public Integer getSamples() {
|
||||
return samples;
|
||||
}
|
||||
|
||||
public void setSamples(Integer samples) {
|
||||
this.samples = samples;
|
||||
}
|
||||
|
||||
public String getAverage() {
|
||||
return average;
|
||||
}
|
||||
|
||||
public void setAverage(String average) {
|
||||
this.average = average;
|
||||
}
|
||||
|
||||
public String getAvgHits() {
|
||||
return avgHits;
|
||||
}
|
||||
|
||||
public void setAvgHits(String avgHits) {
|
||||
this.avgHits = avgHits;
|
||||
}
|
||||
|
||||
public String getTp90() {
|
||||
return tp90;
|
||||
}
|
||||
|
||||
public void setTp90(String tp90) {
|
||||
this.tp90 = tp90;
|
||||
}
|
||||
|
||||
public String getTp95() {
|
||||
return tp95;
|
||||
}
|
||||
|
||||
public void setTp95(String tp95) {
|
||||
this.tp95 = tp95;
|
||||
}
|
||||
|
||||
public String getTp99() {
|
||||
return tp99;
|
||||
}
|
||||
|
||||
public void setTp99(String tp99) {
|
||||
this.tp99 = tp99;
|
||||
}
|
||||
|
||||
public String getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public void setMin(String min) {
|
||||
this.min = min;
|
||||
}
|
||||
|
||||
public String getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public void setMax(String max) {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public String getKbPerSec() {
|
||||
return kbPerSec;
|
||||
}
|
||||
|
||||
public void setKbPerSec(String kbPerSec) {
|
||||
this.kbPerSec = kbPerSec;
|
||||
}
|
||||
|
||||
public String getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
public void setErrors(String errors) {
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
public Integer getKo() {
|
||||
return ko;
|
||||
}
|
||||
|
||||
public void setKo(Integer ko) {
|
||||
this.ko = ko;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
package io.metersphere.report.base;
|
||||
|
||||
public class Statistics {
|
||||
|
||||
private String label;
|
||||
|
||||
private String samples;
|
||||
|
||||
private String ko;
|
||||
|
||||
private String error;
|
||||
|
||||
private String average;
|
||||
|
||||
private String min;
|
||||
|
||||
private String max;
|
||||
|
||||
private String tp90;
|
||||
|
||||
private String tp95;
|
||||
|
||||
private String tp99;
|
||||
|
||||
private String transactions;
|
||||
|
||||
private String received;
|
||||
|
||||
private String sent;
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getSamples() {
|
||||
return samples;
|
||||
}
|
||||
|
||||
public void setSamples(String samples) {
|
||||
this.samples = samples;
|
||||
}
|
||||
|
||||
public String getKo() {
|
||||
return ko;
|
||||
}
|
||||
|
||||
public void setKo(String ko) {
|
||||
this.ko = ko;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public String getAverage() {
|
||||
return average;
|
||||
}
|
||||
|
||||
public void setAverage(String average) {
|
||||
this.average = average;
|
||||
}
|
||||
|
||||
public String getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public void setMin(String min) {
|
||||
this.min = min;
|
||||
}
|
||||
|
||||
public String getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public void setMax(String max) {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public String getTp90() {
|
||||
return tp90;
|
||||
}
|
||||
|
||||
public void setTp90(String tp90) {
|
||||
this.tp90 = tp90;
|
||||
}
|
||||
|
||||
public String getTp95() {
|
||||
return tp95;
|
||||
}
|
||||
|
||||
public void setTp95(String tp95) {
|
||||
this.tp95 = tp95;
|
||||
}
|
||||
|
||||
public String getTp99() {
|
||||
return tp99;
|
||||
}
|
||||
|
||||
public void setTp99(String tp99) {
|
||||
this.tp99 = tp99;
|
||||
}
|
||||
|
||||
public String getTransactions() {
|
||||
return transactions;
|
||||
}
|
||||
|
||||
public void setTransactions(String transactions) {
|
||||
this.transactions = transactions;
|
||||
}
|
||||
|
||||
public String getSent() {
|
||||
return sent;
|
||||
}
|
||||
|
||||
public void setSent(String sent) {
|
||||
this.sent = sent;
|
||||
}
|
||||
|
||||
public String getReceived() {
|
||||
return received;
|
||||
}
|
||||
|
||||
public void setReceived(String received) {
|
||||
this.received = received;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package io.metersphere.report.base;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SummaryData {
|
||||
|
||||
private List<Object> result;
|
||||
|
||||
public List<Object> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(List<Object> result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
package io.metersphere.report.dto;
|
||||
|
||||
import io.metersphere.report.base.ErrorsTop5;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ErrorsTop5DTO {
|
||||
|
||||
private List<ErrorsTop5> errorsTop5List;
|
||||
private String label;
|
||||
private String totalSamples;
|
||||
private String totalErrors;
|
||||
private String error1;
|
||||
private String error1Size;
|
||||
private String error2;
|
||||
private String error2Size;
|
||||
private String error3;
|
||||
private String error3Size;
|
||||
private String error4;
|
||||
private String error4Size;
|
||||
private String error5;
|
||||
private String error5Size;
|
||||
|
||||
public List<ErrorsTop5> getErrorsTop5List() {
|
||||
return errorsTop5List;
|
||||
}
|
||||
|
||||
public void setErrorsTop5List(List<ErrorsTop5> errorsTop5List) {
|
||||
this.errorsTop5List = errorsTop5List;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public String getTotalSamples() {
|
||||
return totalSamples;
|
||||
}
|
||||
|
||||
public void setTotalSamples(String totalSamples) {
|
||||
this.totalSamples = totalSamples;
|
||||
}
|
||||
|
||||
public String getTotalErrors() {
|
||||
return totalErrors;
|
||||
}
|
||||
|
||||
public void setTotalErrors(String totalErrors) {
|
||||
this.totalErrors = totalErrors;
|
||||
}
|
||||
|
||||
public String getError1() {
|
||||
return error1;
|
||||
}
|
||||
|
||||
public void setError1(String error1) {
|
||||
this.error1 = error1;
|
||||
}
|
||||
|
||||
public String getError1Size() {
|
||||
return error1Size;
|
||||
}
|
||||
|
||||
public void setError1Size(String error1Size) {
|
||||
this.error1Size = error1Size;
|
||||
}
|
||||
|
||||
public String getError2() {
|
||||
return error2;
|
||||
}
|
||||
|
||||
public void setError2(String error2) {
|
||||
this.error2 = error2;
|
||||
}
|
||||
|
||||
public String getError2Size() {
|
||||
return error2Size;
|
||||
}
|
||||
|
||||
public void setError2Size(String error2Size) {
|
||||
this.error2Size = error2Size;
|
||||
}
|
||||
|
||||
public String getError3() {
|
||||
return error3;
|
||||
}
|
||||
|
||||
public void setError3(String error3) {
|
||||
this.error3 = error3;
|
||||
}
|
||||
|
||||
public String getError3Size() {
|
||||
return error3Size;
|
||||
}
|
||||
|
||||
public void setError3Size(String error3Size) {
|
||||
this.error3Size = error3Size;
|
||||
}
|
||||
|
||||
public String getError4() {
|
||||
return error4;
|
||||
}
|
||||
|
||||
public void setError4(String error4) {
|
||||
this.error4 = error4;
|
||||
}
|
||||
|
||||
public String getError4Size() {
|
||||
return error4Size;
|
||||
}
|
||||
|
||||
public void setError4Size(String error4Size) {
|
||||
this.error4Size = error4Size;
|
||||
}
|
||||
|
||||
public String getError5() {
|
||||
return error5;
|
||||
}
|
||||
|
||||
public void setError5(String error5) {
|
||||
this.error5 = error5;
|
||||
}
|
||||
|
||||
public String getError5Size() {
|
||||
return error5Size;
|
||||
}
|
||||
|
||||
public void setError5Size(String error5Size) {
|
||||
this.error5Size = error5Size;
|
||||
}
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
package io.metersphere.report.dto;
|
||||
|
||||
import io.metersphere.report.base.RequestStatistics;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RequestStatisticsDTO extends RequestStatistics {
|
||||
|
||||
private List<RequestStatistics> requestStatisticsList;
|
||||
|
||||
private String totalLabel;
|
||||
|
||||
private String totalSamples;
|
||||
|
||||
private String totalErrors;
|
||||
|
||||
private String totalAverage;
|
||||
|
||||
private String totalMin;
|
||||
|
||||
private String totalMax;
|
||||
|
||||
private String totalTP90;
|
||||
|
||||
private String totalTP95;
|
||||
|
||||
private String totalTP99;
|
||||
|
||||
private String totalAvgBandwidth;
|
||||
|
||||
private String totalAvgHits;
|
||||
|
||||
public List<RequestStatistics> getRequestStatisticsList() {
|
||||
return requestStatisticsList;
|
||||
}
|
||||
|
||||
public void setRequestStatisticsList(List<RequestStatistics> requestStatisticsList) {
|
||||
this.requestStatisticsList = requestStatisticsList;
|
||||
}
|
||||
|
||||
public String getTotalLabel() {
|
||||
return totalLabel;
|
||||
}
|
||||
|
||||
public void setTotalLabel(String totalLabel) {
|
||||
this.totalLabel = totalLabel;
|
||||
}
|
||||
|
||||
public String getTotalSamples() {
|
||||
return totalSamples;
|
||||
}
|
||||
|
||||
public void setTotalSamples(String totalSamples) {
|
||||
this.totalSamples = totalSamples;
|
||||
}
|
||||
|
||||
public String getTotalErrors() {
|
||||
return totalErrors;
|
||||
}
|
||||
|
||||
public void setTotalErrors(String totalErrors) {
|
||||
this.totalErrors = totalErrors;
|
||||
}
|
||||
|
||||
public String getTotalAverage() {
|
||||
return totalAverage;
|
||||
}
|
||||
|
||||
public void setTotalAverage(String totalAverage) {
|
||||
this.totalAverage = totalAverage;
|
||||
}
|
||||
|
||||
public String getTotalMin() {
|
||||
return totalMin;
|
||||
}
|
||||
|
||||
public void setTotalMin(String totalMin) {
|
||||
this.totalMin = totalMin;
|
||||
}
|
||||
|
||||
public String getTotalMax() {
|
||||
return totalMax;
|
||||
}
|
||||
|
||||
public void setTotalMax(String totalMax) {
|
||||
this.totalMax = totalMax;
|
||||
}
|
||||
|
||||
public String getTotalTP90() {
|
||||
return totalTP90;
|
||||
}
|
||||
|
||||
public void setTotalTP90(String totalTP90) {
|
||||
this.totalTP90 = totalTP90;
|
||||
}
|
||||
|
||||
public String getTotalTP95() {
|
||||
return totalTP95;
|
||||
}
|
||||
|
||||
public void setTotalTP95(String totalTP95) {
|
||||
this.totalTP95 = totalTP95;
|
||||
}
|
||||
|
||||
public String getTotalTP99() {
|
||||
return totalTP99;
|
||||
}
|
||||
|
||||
public void setTotalTP99(String totalTP99) {
|
||||
this.totalTP99 = totalTP99;
|
||||
}
|
||||
|
||||
public String getTotalAvgBandwidth() {
|
||||
return totalAvgBandwidth;
|
||||
}
|
||||
|
||||
public void setTotalAvgBandwidth(String totalAvgBandwidth) {
|
||||
this.totalAvgBandwidth = totalAvgBandwidth;
|
||||
}
|
||||
|
||||
public String getTotalAvgHits() {
|
||||
return totalAvgHits;
|
||||
}
|
||||
|
||||
public void setTotalAvgHits(String totalAvgHits) {
|
||||
this.totalAvgHits = totalAvgHits;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ import org.apache.jmeter.report.core.SampleMetadata;
|
|||
import org.apache.jmeter.report.dashboard.JsonizerVisitor;
|
||||
import org.apache.jmeter.report.processor.*;
|
||||
import org.apache.jmeter.report.processor.graph.AbstractOverTimeGraphConsumer;
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
@ -14,16 +15,49 @@ import java.time.Instant;
|
|||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.*;
|
||||
|
||||
public class ResultDataParse {
|
||||
|
||||
private static final String DATE_TIME_PATTERN = "yyyy/MM/dd HH:mm:ss";
|
||||
private static final String TIME_PATTERN = "HH:mm:ss";
|
||||
|
||||
public static <T> List<T> summaryMapParsing(Map<String, Object> map, Class<T> clazz) {
|
||||
List<T> list = new ArrayList<>();
|
||||
for (String key : map.keySet()) {
|
||||
MapResultData mapResultData = (MapResultData) map.get(key);
|
||||
ListResultData items = (ListResultData) mapResultData.getResult("items");
|
||||
if (items.getSize() > 0) {
|
||||
for (int i = 0; i < items.getSize(); i++) {
|
||||
MapResultData resultData = (MapResultData) items.get(i);
|
||||
ListResultData data = (ListResultData) resultData.getResult("data");
|
||||
int size = data.getSize();
|
||||
String[] strArray = new String[size];
|
||||
if (size > 0) {
|
||||
T t = null;
|
||||
for (int j = 0; j < size; j++) {
|
||||
ValueResultData valueResultData = (ValueResultData) data.get(j);
|
||||
if (valueResultData.getValue() == null) {
|
||||
strArray[j] = "";
|
||||
} else {
|
||||
String accept = valueResultData.accept(new JsonizerVisitor());
|
||||
strArray[j] = accept.replace("\\", "");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
t = setParam(clazz, strArray);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
list.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<ChartsData> graphMapParsing(Map<String, Object> map, String seriesName) {
|
||||
List<ChartsData> list = new ArrayList<>();
|
||||
// ThreadGroup
|
||||
|
@ -136,4 +170,21 @@ public class ResultDataParse {
|
|||
SimpleDateFormat after = new SimpleDateFormat(TIME_PATTERN);
|
||||
return after.format(before.parse(dateString));
|
||||
}
|
||||
|
||||
private static <T> T setParam(Class<T> clazz, Object[] args)
|
||||
throws Exception {
|
||||
if (clazz == null || args == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
T t = clazz.newInstance();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
if (fields == null || fields.length > args.length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
fields[i].setAccessible(true);
|
||||
fields[i].set(t, args[i]);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -229,6 +230,23 @@ public class PerformanceTestService {
|
|||
}
|
||||
}
|
||||
|
||||
public Map<String, String> log(String testId) {
|
||||
final LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(testId);
|
||||
if (loadTest == null) {
|
||||
MSException.throwException(Translator.get("test_not_found") + testId);
|
||||
}
|
||||
|
||||
if (!StringUtils.equals(loadTest.getStatus(), PerformanceTestStatus.Running.name())) {
|
||||
MSException.throwException(Translator.get("test_not_running"));
|
||||
}
|
||||
|
||||
Engine engine = EngineFactory.createEngine(loadTest);
|
||||
if (engine == null) {
|
||||
MSException.throwException(String.format("Engine is null,test ID:%s", testId));
|
||||
}
|
||||
return engine.log();
|
||||
}
|
||||
|
||||
public List<LoadTestDTO> recentTestPlans(QueryTestPlanRequest request) {
|
||||
// 查询最近的测试计划
|
||||
request.setRecent(true);
|
||||
|
@ -260,4 +278,5 @@ public class PerformanceTestService {
|
|||
example.createCriteria().andTestResourcePoolIdEqualTo(resourcePoolId);
|
||||
return loadTestMapper.selectByExampleWithBLOBs(example);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,16 +12,10 @@ import io.metersphere.dto.ReportDTO;
|
|||
import io.metersphere.engine.Engine;
|
||||
import io.metersphere.engine.EngineFactory;
|
||||
import io.metersphere.report.GenerateReport;
|
||||
import io.metersphere.report.base.ChartsData;
|
||||
import io.metersphere.report.base.Errors;
|
||||
import io.metersphere.report.base.ReportTimeInfo;
|
||||
import io.metersphere.report.base.TestOverview;
|
||||
import io.metersphere.report.dto.ErrorsTop5DTO;
|
||||
import io.metersphere.report.dto.RequestStatisticsDTO;
|
||||
import io.metersphere.report.base.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -86,12 +80,11 @@ public class ReportService {
|
|||
return extLoadTestReportMapper.getReportTestAndProInfo(reportId);
|
||||
}
|
||||
|
||||
public RequestStatisticsDTO getReport(String id) {
|
||||
public List<Statistics> getReport(String id) {
|
||||
checkReportStatus(id);
|
||||
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
|
||||
String content = loadTestReport.getContent();
|
||||
RequestStatisticsDTO requestStatistics = GenerateReport.getRequestStatistics(content);
|
||||
return requestStatistics;
|
||||
return GenerateReport.getRequestStatistics(content);
|
||||
}
|
||||
|
||||
public List<Errors> getReportErrors(String id) {
|
||||
|
@ -102,12 +95,12 @@ public class ReportService {
|
|||
return errors;
|
||||
}
|
||||
|
||||
public ErrorsTop5DTO getReportErrorsTOP5(String id) {
|
||||
public List<ErrorsTop5> getReportErrorsTOP5(String id) {
|
||||
checkReportStatus(id);
|
||||
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
|
||||
String content = loadTestReport.getContent();
|
||||
ErrorsTop5DTO errors = GenerateReport.getErrorsTop5DTO(content);
|
||||
return errors;
|
||||
List<ErrorsTop5> errorsTop5 = GenerateReport.getErrorsTop5List(content);
|
||||
return errorsTop5;
|
||||
}
|
||||
|
||||
public TestOverview getTestOverview(String id) {
|
||||
|
@ -119,7 +112,6 @@ public class ReportService {
|
|||
}
|
||||
|
||||
public ReportTimeInfo getReportTimeInfo(String id) {
|
||||
checkReportStatus(id);
|
||||
LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id);
|
||||
String content = loadTestReport.getContent();
|
||||
ReportTimeInfo reportTimeInfo = GenerateReport.getReportTimeInfo(content);
|
||||
|
|
|
@ -19,4 +19,6 @@ duplicate_node_ip=Duplicate IPs
|
|||
only_one_k8s=Only one K8s can be added
|
||||
organization_id_is_null=Organization ID cannot be null
|
||||
max_thread_insufficient=The number of concurrent users exceeds
|
||||
cannot_edit_load_test_running=Cannot modify the running test
|
||||
cannot_edit_load_test_running=Cannot modify the running test
|
||||
test_not_found=Test cannot be found:
|
||||
test_not_running=Test is not running
|
|
@ -19,4 +19,6 @@ duplicate_node_ip=节点 IP 重复
|
|||
only_one_k8s=只能添加一个 K8s
|
||||
organization_id_is_null=组织 ID 不能为空
|
||||
max_thread_insufficient=并发用户数超额
|
||||
cannot_edit_load_test_running=不能修改正在运行的测试
|
||||
cannot_edit_load_test_running=不能修改正在运行的测试
|
||||
test_not_found=测试不存在:
|
||||
test_not_running=测试未运行
|
|
@ -1,10 +1,8 @@
|
|||
package io.metersphere;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.opencsv.bean.CsvToBean;
|
||||
import com.opencsv.bean.CsvToBeanBuilder;
|
||||
import com.opencsv.bean.HeaderColumnNameMappingStrategy;
|
||||
import io.metersphere.report.base.RequestStatistics;
|
||||
import org.junit.Test;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
@ -201,73 +199,6 @@ public class JtlTest {
|
|||
List<Metric> metrics = beanBuilderExample(jtlString);
|
||||
// 根据label分组,label作为map的key
|
||||
Map<String, List<Metric>> map = metrics.stream().collect(Collectors.groupingBy(Metric::getLabel));
|
||||
getOneRpsResult(map);
|
||||
}
|
||||
|
||||
private void getOneRpsResult(Map<String, List<Metric>> map){
|
||||
Iterator<Map.Entry<String, List<Metric>>> iterator = map.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, List<Metric>> entry = iterator.next();
|
||||
String label = entry.getKey();
|
||||
List<Metric> list = entry.getValue();
|
||||
List<String> timestampList = list.stream().map(Metric::getTimestamp).collect(Collectors.toList());
|
||||
int index=0;
|
||||
//总的响应时间
|
||||
int sumElapsed=0;
|
||||
Integer failSize = 0;
|
||||
Integer totalBytes = 0;
|
||||
// 响应时间的列表排序之后 用于计算90%line、95%line、99line
|
||||
List<Integer> elapsedList = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
try {
|
||||
Metric row = list.get(i);
|
||||
//响应时间
|
||||
String elapsed = row.getElapsed();
|
||||
sumElapsed += Integer.valueOf(elapsed);
|
||||
elapsedList.add(Integer.valueOf(elapsed));
|
||||
//成功与否
|
||||
String success = row.getSuccess();
|
||||
if (!"true".equals(success)){
|
||||
failSize++;
|
||||
}
|
||||
//字节
|
||||
String bytes = row.getBytes();
|
||||
totalBytes += Integer.valueOf(bytes);
|
||||
|
||||
index++;
|
||||
}catch (Exception e){
|
||||
System.out.println("exception i:"+i);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(elapsedList, new Comparator<Integer>() {
|
||||
public int compare(Integer o1, Integer o2) {
|
||||
return o1-o2;
|
||||
}
|
||||
});
|
||||
|
||||
Integer tp90 = elapsedList.size()*9/10;
|
||||
Integer tp95 = elapsedList.size()*95/100;
|
||||
Integer tp99 = elapsedList.size()*99/100;
|
||||
|
||||
Long l = Long.valueOf(timestampList.get(index-1)) - Long.valueOf(timestampList.get(0));
|
||||
|
||||
RequestStatistics sceneResult = new RequestStatistics();
|
||||
sceneResult.setRequestLabel(label);
|
||||
sceneResult.setSamples(index);
|
||||
// sceneResult.setAverage(sumElapsed/index);
|
||||
sceneResult.setTp90(elapsedList.get(tp90)+"");
|
||||
sceneResult.setTp95(elapsedList.get(tp95)+"");
|
||||
sceneResult.setTp99(elapsedList.get(tp99)+"");
|
||||
sceneResult.setMin(elapsedList.get(0)+"");
|
||||
sceneResult.setMax(elapsedList.get(index-1)+"");
|
||||
sceneResult.setErrors(String.format("%.2f",failSize*100.0/index)+"%");
|
||||
sceneResult.setKbPerSec(String.format("%.2f",totalBytes*1.0/1024/(l*1.0/1000)));
|
||||
System.out.println(JSONObject.toJSONString(sceneResult));
|
||||
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package io.metersphere;
|
||||
|
||||
import io.metersphere.report.base.Statistics;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class ResultDataParseTest {
|
||||
|
||||
String[] s = {"1","2","3","4","5","6","7","8","9","10","11","12","13"};
|
||||
|
||||
public static <T> T setParam(Class<T> clazz, Object[] args)
|
||||
throws Exception {
|
||||
if (clazz == null || args == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
T t = clazz.newInstance();
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
if (fields == null || fields.length > args.length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
fields[i].setAccessible(true);
|
||||
fields[i].set(t, args[i]);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
Statistics statistics = setParam(Statistics.class, s);
|
||||
System.out.println(statistics.toString());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
|
||||
<el-input
|
||||
class="search"
|
||||
type="text"
|
||||
size="small"
|
||||
:placeholder="$t('commons.search_by_name')"
|
||||
prefix-icon="el-icon-search"
|
||||
@change="search"
|
||||
maxlength="60"
|
||||
v-model="condition.name" clearable/>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MsTableSearchBar",
|
||||
props: {
|
||||
condition: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
search() {
|
||||
this.$emit('update:condition', this.condition);
|
||||
this.$emit('change');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -1,11 +1,9 @@
|
|||
<template>
|
||||
|
||||
|
||||
<el-tooltip :disabled="disabled"
|
||||
:content="tip"
|
||||
placement="bottom"
|
||||
:effect="effect">
|
||||
|
||||
<el-button @click="exec()"
|
||||
circle
|
||||
:type="type"
|
||||
|
|
|
@ -49,6 +49,13 @@
|
|||
</el-tabs>
|
||||
|
||||
</el-card>
|
||||
<el-dialog :title="title" :visible.sync="showTestLogging">
|
||||
<el-tabs type="border-card" :stretch="true">
|
||||
<el-tab-pane v-for="(item, key) in testLogging" :key="key" :label="key" class="logging-content">
|
||||
{{item}}
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -79,15 +86,18 @@
|
|||
startTime: '0',
|
||||
endTime: '0',
|
||||
minutes: '0',
|
||||
seconds: '0'
|
||||
seconds: '0',
|
||||
title: 'Logging',
|
||||
testLogging: null,
|
||||
showTestLogging: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initBreadcrumb() {
|
||||
if(this.reportId){
|
||||
if (this.reportId) {
|
||||
this.result = this.$get("/performance/report/test/pro/info/" + this.reportId, res => {
|
||||
let data = res.data;
|
||||
if(data){
|
||||
if (data) {
|
||||
this.reportName = data.name;
|
||||
this.testName = data.testName;
|
||||
this.projectName = data.projectName;
|
||||
|
@ -96,10 +106,10 @@
|
|||
}
|
||||
},
|
||||
initReportTimeInfo() {
|
||||
if(this.reportId){
|
||||
if (this.reportId) {
|
||||
this.result = this.$get("/performance/report/content/report_time/" + this.reportId, res => {
|
||||
let data = res.data;
|
||||
if(data){
|
||||
if (data) {
|
||||
this.startTime = data.startTime;
|
||||
this.endTime = data.endTime;
|
||||
let duration = data.duration;
|
||||
|
@ -108,23 +118,37 @@
|
|||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
getLog(testId) {
|
||||
this.result = this.$get('/performance/log/' + testId, response => {
|
||||
this.testLogging = response.data;
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.reportId = this.$route.path.split('/')[4];
|
||||
this.$get("/performance/report/" + this.reportId, res => {
|
||||
this.result = this.$get("/performance/report/" + this.reportId, res => {
|
||||
let data = res.data;
|
||||
this.status = data.status;
|
||||
if (data.status === "Error") {
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: "报告生成错误,无法查看!"
|
||||
});
|
||||
} else if (data.status === "Starting") {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: "报告生成中...."
|
||||
});
|
||||
switch (data.status) {
|
||||
case 'Error':
|
||||
this.$message({
|
||||
type: 'warning',
|
||||
message: "报告生成错误,无法查看!"
|
||||
});
|
||||
break;
|
||||
case 'Starting':
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: "报告生成中...."
|
||||
});
|
||||
break;
|
||||
case 'Running':
|
||||
this.showTestLogging = true;
|
||||
this.getLog(data.testId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
})
|
||||
this.initBreadcrumb();
|
||||
|
@ -133,10 +157,10 @@
|
|||
watch: {
|
||||
'$route'(to) {
|
||||
let reportId = to.path.split('/')[4];
|
||||
if(reportId){
|
||||
if (reportId) {
|
||||
this.$get("/performance/report/test/pro/info/" + reportId, response => {
|
||||
let data = response.data;
|
||||
if(data){
|
||||
if (data) {
|
||||
this.reportName = data.name;
|
||||
this.testName = data.testName;
|
||||
this.projectName = data.projectName;
|
||||
|
@ -144,7 +168,7 @@
|
|||
});
|
||||
this.result = this.$get("/performance/report/content/report_time/" + this.reportId, res => {
|
||||
let data = res.data;
|
||||
if(data){
|
||||
if (data) {
|
||||
this.startTime = data.startTime;
|
||||
this.endTime = data.endTime;
|
||||
let duration = data.duration;
|
||||
|
@ -170,4 +194,10 @@
|
|||
display: block;
|
||||
color: #5C7878;
|
||||
}
|
||||
|
||||
.logging-content {
|
||||
white-space: pre-line;
|
||||
height: calc(100vh - 450px);
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
stripe
|
||||
style="width: 100%"
|
||||
show-summary
|
||||
:summary-method="getSummaries"
|
||||
>
|
||||
<el-table-column
|
||||
prop="sample"
|
||||
|
@ -59,62 +58,65 @@
|
|||
width="100"
|
||||
>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="error"
|
||||
prop="error1"
|
||||
label="Error"
|
||||
width="400"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="errors"
|
||||
prop="error1Size"
|
||||
label="#Errors"
|
||||
width="100"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="Error"
|
||||
prop="error2"
|
||||
label="Error"
|
||||
width="400"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="#Errors"
|
||||
prop="error2Size"
|
||||
label="#Errors"
|
||||
width="100"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="Error"
|
||||
prop="error3"
|
||||
label="Error"
|
||||
width="400"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="#Errors"
|
||||
prop="error3Size"
|
||||
label="#Errors"
|
||||
width="100"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="Error"
|
||||
prop="error4"
|
||||
label="Error"
|
||||
width="400"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="#Errors"
|
||||
prop="error4Size"
|
||||
label="#Errors"
|
||||
width="100"
|
||||
>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="Error"
|
||||
prop="error5"
|
||||
label="Error"
|
||||
width="400"
|
||||
>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="#Errors"
|
||||
prop="error5Size"
|
||||
label="#Errors"
|
||||
width="100"
|
||||
>
|
||||
|
@ -128,22 +130,7 @@
|
|||
name: "ErrorLog",
|
||||
data() {
|
||||
return {
|
||||
tableData: [{},{},{},{},{}],
|
||||
errorTotal: {
|
||||
label: '',
|
||||
totalSamples: '',
|
||||
totalErrors: '',
|
||||
error1: '',
|
||||
error1Size: '',
|
||||
error2: '',
|
||||
error2Size: '',
|
||||
error3: '',
|
||||
error3Size: '',
|
||||
error4: '',
|
||||
error4Size: '',
|
||||
error5: '',
|
||||
error5Size: ''
|
||||
},
|
||||
tableData: [],
|
||||
errorTop5: []
|
||||
}
|
||||
},
|
||||
|
@ -153,33 +140,14 @@
|
|||
this.tableData = res.data;
|
||||
})
|
||||
this.$get("/performance/report/content/errors_top5/" + this.id, res => {
|
||||
this.errorTotal = res.data
|
||||
this.errorTop5 = res.data.errorsTop5List;
|
||||
this.errorTop5 = res.data;
|
||||
})
|
||||
},
|
||||
getSummaries () {
|
||||
const sums = []
|
||||
sums[0] = this.errorTotal.label;
|
||||
sums[1] = this.errorTotal.totalSamples;
|
||||
sums[2] = this.errorTotal.totalErrors;
|
||||
sums[3] = this.errorTotal.error1;
|
||||
sums[4] = this.errorTotal.error1Size;
|
||||
sums[5] = this.errorTotal.error2;
|
||||
sums[6] = this.errorTotal.error2Size;
|
||||
sums[7] = this.errorTotal.error3;
|
||||
sums[8] = this.errorTotal.error3Size;
|
||||
sums[9] = this.errorTotal.error4;
|
||||
sums[10] = this.errorTotal.error4Size;
|
||||
sums[11] = this.errorTotal.error5;
|
||||
sums[12] = this.errorTotal.error5Size;
|
||||
return sums;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
status() {
|
||||
if ("Completed" === this.status) {
|
||||
this.initTableData()
|
||||
this.getSummaries()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
border
|
||||
style="width: 100%"
|
||||
show-summary
|
||||
:summary-method="getSummaries"
|
||||
:default-sort = "{prop: 'samples', order: 'descending'}"
|
||||
>
|
||||
<el-table-column label="Requests" fixed width="450" align="center">
|
||||
<el-table-column
|
||||
prop="requestLabel"
|
||||
prop="label"
|
||||
label="Label"
|
||||
width="450"/>
|
||||
</el-table-column>
|
||||
|
@ -25,7 +24,13 @@
|
|||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="errors"
|
||||
prop="ko"
|
||||
label="KO%"
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
prop="error"
|
||||
label="Error%"
|
||||
align="center"
|
||||
/>
|
||||
|
@ -58,18 +63,29 @@
|
|||
/>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="avgHits"
|
||||
label="Avg Hits/s"
|
||||
width="100"
|
||||
/>
|
||||
<el-table-column label="Throughput">
|
||||
<el-table-column
|
||||
prop="transactions"
|
||||
label="Transactions"
|
||||
width="100"
|
||||
/>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="NetWork(KB/sec)" align="center">
|
||||
<el-table-column
|
||||
prop="received"
|
||||
label="Received"
|
||||
align="center"
|
||||
width="200"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="sent"
|
||||
label="Sent"
|
||||
align="center"
|
||||
width="200"
|
||||
/>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="kbPerSec"
|
||||
label="Avg Bandwidth(KBytes/s)"
|
||||
align="center"
|
||||
width="200"
|
||||
/>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -79,50 +95,20 @@
|
|||
name: "RequestStatistics",
|
||||
data() {
|
||||
return {
|
||||
tableData: [{},{},{},{},{}],
|
||||
totalInfo: {
|
||||
totalLabel: '',
|
||||
totalSamples: '',
|
||||
totalErrors: '',
|
||||
totalAverage: '',
|
||||
totalMin: '',
|
||||
totalMax: '',
|
||||
totalTP90: '',
|
||||
totalTP95: '',
|
||||
totalTP99: '',
|
||||
totalAvgHits: '',
|
||||
totalAvgBandwidth: ''
|
||||
}
|
||||
tableData: [{},{},{},{},{}]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initTableData() {
|
||||
this.$get("/performance/report/content/" + this.id, res => {
|
||||
this.tableData = res.data.requestStatisticsList;
|
||||
this.totalInfo = res.data;
|
||||
this.tableData = res.data;
|
||||
})
|
||||
},
|
||||
getSummaries () {
|
||||
const sums = []
|
||||
sums[0] = this.totalInfo.totalLabel;
|
||||
sums[1] = this.totalInfo.totalSamples;
|
||||
sums[2] = this.totalInfo.totalErrors;
|
||||
sums[3] = this.totalInfo.totalAverage;
|
||||
sums[4] = this.totalInfo.totalMin;
|
||||
sums[5] = this.totalInfo.totalMax;
|
||||
sums[6] = this.totalInfo.totalTP90;
|
||||
sums[7] = this.totalInfo.totalTP95;
|
||||
sums[8] = this.totalInfo.totalTP99;
|
||||
sums[9] = this.totalInfo.totalAvgHits;
|
||||
sums[10] = this.totalInfo.totalAvgBandwidth;
|
||||
return sums;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
status() {
|
||||
if ("Completed" === this.status) {
|
||||
this.initTableData()
|
||||
this.getSummaries()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -9,16 +9,19 @@
|
|||
@dataChange="changeProject">
|
||||
</select-menu>
|
||||
<node-tree class="node-tree"
|
||||
:current-project="currentProject"
|
||||
@nodeSelectEvent="refreshTable"
|
||||
@refresh="refreshTable"
|
||||
ref="nodeTree">
|
||||
</node-tree>
|
||||
v-loading="result.loading"
|
||||
@nodeSelectEvent="nodeChange"
|
||||
@refresh="refresh"
|
||||
:tree-nodes="treeNodes"
|
||||
:type="'edit'"
|
||||
ref="nodeTree"/>
|
||||
</el-aside>
|
||||
|
||||
<el-main class="test-case-list">
|
||||
<test-case-list
|
||||
:current-project="currentProject"
|
||||
:selectNodeIds="selectNodeIds"
|
||||
:selectNodeNames="selectNodeNames"
|
||||
@openTestCaseEditDialog="openTestCaseEditDialog"
|
||||
@testCaseEdit="openTestCaseEditDialog"
|
||||
@refresh="refresh"
|
||||
|
@ -29,17 +32,17 @@
|
|||
|
||||
<test-case-edit
|
||||
@refresh="refreshTable"
|
||||
:tree-nodes="treeNodes"
|
||||
ref="testCaseEditDialog">
|
||||
</test-case-edit>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import NodeTree from './components/NodeTree';
|
||||
import NodeTree from '../common/NodeTree';
|
||||
import TestCaseEdit from './components/TestCaseEdit';
|
||||
import {CURRENT_PROJECT, WORKSPACE_ID} from '../../../../common/js/constants';
|
||||
import {CURRENT_PROJECT} from '../../../../common/js/constants';
|
||||
import TestCaseList from "./components/TestCaseList";
|
||||
import SelectMenu from "../common/SelectMenu";
|
||||
|
||||
|
@ -50,20 +53,19 @@
|
|||
data() {
|
||||
return {
|
||||
result: {},
|
||||
tableData: [],
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
total: 0,
|
||||
projects: [],
|
||||
currentProject: null,
|
||||
treeNodes: []
|
||||
treeNodes: [],
|
||||
selectNodeIds: [],
|
||||
selectNodeNames: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getProjects();
|
||||
},
|
||||
mounted() {
|
||||
this.getProjects();
|
||||
this.refresh();
|
||||
if (this.$route.params.projectId){
|
||||
this.getProjectById(this.$route.params.projectId)
|
||||
}
|
||||
|
@ -77,11 +79,16 @@
|
|||
let path = to.path;
|
||||
if (to.params.projectId){
|
||||
this.getProjectById(to.params.projectId)
|
||||
this.getProjects();
|
||||
}
|
||||
if (path.indexOf("/track/case/edit") >= 0){
|
||||
this.openRecentTestCaseEditDialog();
|
||||
this.$router.push('/track/case/all');
|
||||
this.getProjects();
|
||||
}
|
||||
},
|
||||
currentProject() {
|
||||
this.refresh();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -90,7 +97,7 @@
|
|||
this.projects = response.data;
|
||||
let lastProject = JSON.parse(localStorage.getItem(CURRENT_PROJECT));
|
||||
if (lastProject) {
|
||||
let hasCurrentProject = false;
|
||||
let hasCurrentProject = false;
|
||||
for (let i = 0; i < this.projects.length; i++) {
|
||||
if (this.projects[i].id == lastProject.id) {
|
||||
this.currentProject = lastProject;
|
||||
|
@ -122,37 +129,15 @@
|
|||
changeProject(project) {
|
||||
this.setCurrentProject(project);
|
||||
},
|
||||
refreshTable(data) {
|
||||
this.$refs.testCaseList.initTableData(data);
|
||||
nodeChange(nodeIds, nodeNames) {
|
||||
this.selectNodeIds = nodeIds;
|
||||
this.selectNodeNames = nodeNames;
|
||||
},
|
||||
openTestCaseEditDialog(data) {
|
||||
this.setNodePathOption(this.$refs.nodeTree.treeNodes);
|
||||
this.setMaintainerOptions();
|
||||
this.$refs.testCaseEditDialog.openTestCaseEditDialog(data);
|
||||
refreshTable() {
|
||||
this.$refs.testCaseList.initTableData();
|
||||
},
|
||||
setNodePathOption(nodes) {
|
||||
let moduleOptions = [];
|
||||
nodes.forEach(node => {
|
||||
this.buildNodePath(node, {path: ''}, moduleOptions);
|
||||
});
|
||||
this.$refs.testCaseEditDialog.moduleOptions = moduleOptions;
|
||||
},
|
||||
buildNodePath(node, option, moduleOptions) {
|
||||
//递归构建节点路径
|
||||
option.id = node.id;
|
||||
option.path = option.path + '/' + node.name;
|
||||
moduleOptions.push(option);
|
||||
if (node.children) {
|
||||
for (let i = 0; i < node.children.length; i++){
|
||||
this.buildNodePath(node.children[i], { path: option.path }, moduleOptions);
|
||||
}
|
||||
}
|
||||
},
|
||||
setMaintainerOptions() {
|
||||
let workspaceId = localStorage.getItem(WORKSPACE_ID);
|
||||
this.$post('/user/ws/member/list/all', {workspaceId:workspaceId}, response => {
|
||||
this.$refs.testCaseEditDialog.maintainerOptions = response.data;
|
||||
});
|
||||
openTestCaseEditDialog(testCase) {
|
||||
this.$refs.testCaseEditDialog.open(testCase);
|
||||
},
|
||||
getProjectByCaseId(caseId) {
|
||||
return this.$get('/test/case/project/' + caseId, async response => {
|
||||
|
@ -160,9 +145,10 @@
|
|||
});
|
||||
},
|
||||
refresh() {
|
||||
this.selectNodeIds = [];
|
||||
this.selectNodeNames = [];
|
||||
this.$refs.testCaseList.initTableData();
|
||||
this.$refs.nodeTree.getNodeTree();
|
||||
this.getProjects();
|
||||
this.getNodeTree();
|
||||
},
|
||||
openRecentTestCaseEditDialog() {
|
||||
let caseId = this.$route.params.caseId;
|
||||
|
@ -190,8 +176,14 @@
|
|||
localStorage.setItem(CURRENT_PROJECT, JSON.stringify(project));
|
||||
}
|
||||
this.refresh();
|
||||
},
|
||||
getNodeTree() {
|
||||
if (this.currentProject) {
|
||||
this.result = this.$get("/case/node/list/" + this.currentProject.id, response => {
|
||||
this.treeNodes = response.data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -216,13 +208,8 @@
|
|||
margin-left: 0;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
/*background: white;*/
|
||||
}
|
||||
|
||||
.test-case-list {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
|
|
@ -167,18 +167,11 @@
|
|||
</el-form>
|
||||
|
||||
<template v-slot:footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button
|
||||
@click="dialogFormVisible = false">
|
||||
{{$t('test_track.cancel')}}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="saveCase">
|
||||
{{$t('test_track.confirm')}}
|
||||
</el-button>
|
||||
</div>
|
||||
<ms-dialog-footer
|
||||
@cancel="dialogFormVisible = false"
|
||||
@confirm="saveCase"/>
|
||||
</template>
|
||||
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
|
@ -188,126 +181,163 @@
|
|||
|
||||
<script>
|
||||
|
||||
import {CURRENT_PROJECT} from '../../../../../common/js/constants';
|
||||
import {CURRENT_PROJECT, WORKSPACE_ID} from '../../../../../common/js/constants';
|
||||
import MsDialogFooter from '../../../common/components/MsDialogFooter'
|
||||
|
||||
|
||||
export default {
|
||||
name: "TestCaseEdit",
|
||||
data() {
|
||||
return {
|
||||
dialogFormVisible: false,
|
||||
form: {
|
||||
name: '',
|
||||
module: '',
|
||||
maintainer: '',
|
||||
priority: '',
|
||||
type: '',
|
||||
method: '',
|
||||
prerequisite: '',
|
||||
steps: [{
|
||||
num: 1 ,
|
||||
desc: '',
|
||||
result: ''
|
||||
}],
|
||||
remark: '',
|
||||
},
|
||||
moduleOptions: [],
|
||||
maintainerOptions: [],
|
||||
rules:{
|
||||
name :[
|
||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||
{ max: 30, message: this.$t('test_track.length_less_than') + '30', trigger: 'blur' }
|
||||
],
|
||||
module :[{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
|
||||
maintainer :[{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
|
||||
priority :[{required: true, message: this.$t('test_track.case.input_priority'), trigger: 'change'}],
|
||||
type :[{required: true, message: this.$t('test_track.case.input_type'), trigger: 'change'}],
|
||||
method :[{required: true, message: this.$t('test_track.case.input_method'), trigger: 'change'}]
|
||||
},
|
||||
formLabelWidth: "120px",
|
||||
operationType: ''
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openTestCaseEditDialog(testCase) {
|
||||
this.resetForm();
|
||||
this.operationType = 'add';
|
||||
if(testCase){
|
||||
//修改
|
||||
this.operationType = 'edit';
|
||||
let tmp = {};
|
||||
Object.assign(tmp, testCase);
|
||||
tmp.steps = JSON.parse(testCase.steps);
|
||||
Object.assign(this.form, tmp);
|
||||
this.form.module = testCase.nodeId;
|
||||
}
|
||||
this.dialogFormVisible = true;
|
||||
},
|
||||
handleAddStep(index, data) {
|
||||
let step = {};
|
||||
step.num = data.num + 1;
|
||||
step.desc = null;
|
||||
step.result = null;
|
||||
this.form.steps.forEach(step => {
|
||||
if(step.num > data.num){
|
||||
step.num ++;
|
||||
}
|
||||
});
|
||||
this.form.steps.push(step);
|
||||
},
|
||||
handleDeleteStep(index, data) {
|
||||
this.form.steps.splice(index, 1);
|
||||
this.form.steps.forEach(step => {
|
||||
if(step.num > data.num){
|
||||
step.num --;
|
||||
}
|
||||
});
|
||||
},
|
||||
saveCase(){
|
||||
this.$refs['caseFrom'].validate((valid) => {
|
||||
if (valid) {
|
||||
let param = {};
|
||||
Object.assign(param, this.form);
|
||||
param.steps = JSON.stringify(this.form.steps);
|
||||
param.nodeId = this.form.module;
|
||||
this.moduleOptions.forEach(item => {
|
||||
if(this.form.module === item.id){
|
||||
param.nodePath = item.path;
|
||||
}
|
||||
});
|
||||
if(localStorage.getItem(CURRENT_PROJECT)) {
|
||||
param.projectId = JSON.parse(localStorage.getItem(CURRENT_PROJECT)).id;
|
||||
}
|
||||
this.$post('/test/case/' + this.operationType, param, () => {
|
||||
this.$message.success(this.$t('commons.save_success'));
|
||||
this.dialogFormVisible = false;
|
||||
this.$emit("refresh");
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
,
|
||||
resetForm() {
|
||||
if (this.$refs['caseFrom']) {
|
||||
this.$refs['caseFrom'].resetFields();
|
||||
}
|
||||
this.form.name = '';
|
||||
this.form.module = '';
|
||||
this.form.type = '';
|
||||
this.form.method = '';
|
||||
this.form.maintainer = '';
|
||||
this.form.priority = '';
|
||||
this.form.prerequisite = '';
|
||||
this.form.remark = '';
|
||||
this.form.steps = [{
|
||||
name: "TestCaseEdit",
|
||||
components: {MsDialogFooter},
|
||||
data() {
|
||||
return {
|
||||
dialogFormVisible: false,
|
||||
form: {
|
||||
name: '',
|
||||
module: '',
|
||||
maintainer: '',
|
||||
priority: '',
|
||||
type: '',
|
||||
method: '',
|
||||
prerequisite: '',
|
||||
steps: [{
|
||||
num: 1 ,
|
||||
desc: '',
|
||||
result: ''
|
||||
}];
|
||||
}],
|
||||
remark: '',
|
||||
},
|
||||
moduleOptions: [],
|
||||
maintainerOptions: [],
|
||||
workspaceId: '',
|
||||
rules:{
|
||||
name :[
|
||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||
{ max: 30, message: this.$t('test_track.length_less_than') + '30', trigger: 'blur' }
|
||||
],
|
||||
module :[{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
|
||||
maintainer :[{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
|
||||
priority :[{required: true, message: this.$t('test_track.case.input_priority'), trigger: 'change'}],
|
||||
type :[{required: true, message: this.$t('test_track.case.input_type'), trigger: 'change'}],
|
||||
method :[{required: true, message: this.$t('test_track.case.input_method'), trigger: 'change'}]
|
||||
},
|
||||
formLabelWidth: "120px",
|
||||
operationType: ''
|
||||
};
|
||||
},
|
||||
props: {
|
||||
treeNodes: {
|
||||
type: Array
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(testCase) {
|
||||
this.resetForm();
|
||||
this.getSelectOptions();
|
||||
this.operationType = 'add';
|
||||
if(testCase){
|
||||
//修改
|
||||
this.operationType = 'edit';
|
||||
let tmp = {};
|
||||
Object.assign(tmp, testCase);
|
||||
tmp.steps = JSON.parse(testCase.steps);
|
||||
Object.assign(this.form, tmp);
|
||||
this.form.module = testCase.nodeId;
|
||||
}
|
||||
this.dialogFormVisible = true;
|
||||
},
|
||||
handleAddStep(index, data) {
|
||||
let step = {};
|
||||
step.num = data.num + 1;
|
||||
step.desc = null;
|
||||
step.result = null;
|
||||
this.form.steps.forEach(step => {
|
||||
if(step.num > data.num){
|
||||
step.num ++;
|
||||
}
|
||||
});
|
||||
this.form.steps.push(step);
|
||||
},
|
||||
handleDeleteStep(index, data) {
|
||||
this.form.steps.splice(index, 1);
|
||||
this.form.steps.forEach(step => {
|
||||
if(step.num > data.num){
|
||||
step.num --;
|
||||
}
|
||||
});
|
||||
},
|
||||
saveCase(){
|
||||
this.$refs['caseFrom'].validate((valid) => {
|
||||
if (valid) {
|
||||
let param = {};
|
||||
Object.assign(param, this.form);
|
||||
param.steps = JSON.stringify(this.form.steps);
|
||||
param.nodeId = this.form.module;
|
||||
this.moduleOptions.forEach(item => {
|
||||
if(this.form.module === item.id){
|
||||
param.nodePath = item.path;
|
||||
}
|
||||
});
|
||||
if(localStorage.getItem(CURRENT_PROJECT)) {
|
||||
param.projectId = JSON.parse(localStorage.getItem(CURRENT_PROJECT)).id;
|
||||
}
|
||||
this.$post('/test/case/' + this.operationType, param, () => {
|
||||
this.$message.success(this.$t('commons.save_success'));
|
||||
this.dialogFormVisible = false;
|
||||
this.$emit("refresh");
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
getModuleOptions() {
|
||||
let moduleOptions = [];
|
||||
this.treeNodes.forEach(node => {
|
||||
this.buildNodePath(node, {path: ''}, moduleOptions);
|
||||
});
|
||||
this.moduleOptions = moduleOptions;
|
||||
},
|
||||
getMaintainerOptions() {
|
||||
let workspaceId = localStorage.getItem(WORKSPACE_ID);
|
||||
this.$post('/user/ws/member/list/all', {workspaceId:workspaceId}, response => {
|
||||
this.maintainerOptions = response.data;
|
||||
});
|
||||
},
|
||||
getSelectOptions() {
|
||||
this.getModuleOptions();
|
||||
this.getMaintainerOptions();
|
||||
},
|
||||
buildNodePath(node, option, moduleOptions) {
|
||||
//递归构建节点路径
|
||||
option.id = node.id;
|
||||
option.path = option.path + '/' + node.name;
|
||||
moduleOptions.push(option);
|
||||
if (node.children) {
|
||||
for (let i = 0; i < node.children.length; i++){
|
||||
this.buildNodePath(node.children[i], { path: option.path }, moduleOptions);
|
||||
}
|
||||
}
|
||||
},
|
||||
resetForm() {
|
||||
if (this.$refs['caseFrom']) {
|
||||
this.$refs['caseFrom'].resetFields();
|
||||
}
|
||||
this.form.name = '';
|
||||
this.form.module = '';
|
||||
this.form.type = '';
|
||||
this.form.method = '';
|
||||
this.form.maintainer = '';
|
||||
this.form.priority = '';
|
||||
this.form.prerequisite = '';
|
||||
this.form.remark = '';
|
||||
this.form.steps = [{
|
||||
num: 1 ,
|
||||
desc: '',
|
||||
result: ''
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
<li v-for="errFile in errList" :key="errFile.rowNum">
|
||||
{{errFile.errMsg}}
|
||||
</li>
|
||||
</ul></el-row>
|
||||
</ul>
|
||||
</el-row>
|
||||
|
||||
</el-dialog>
|
||||
|
||||
|
|
|
@ -5,20 +5,18 @@
|
|||
<template v-slot:header>
|
||||
<div>
|
||||
<el-row type="flex" justify="space-between" align="middle">
|
||||
<span class="title">{{$t('test_track.case.test_case')}}
|
||||
<ms-create-box :tips="$t('test_track.case.create')" :exec="testCaseCreate"/></span>
|
||||
|
||||
<node-breadcrumb
|
||||
:node-names="selectNodeNames"
|
||||
@refresh="refresh"/>
|
||||
|
||||
<span class="operate-button">
|
||||
<ms-create-box :tips="$t('test_track.case.create')" :exec="testCaseCreate"/>
|
||||
<test-case-import :projectId="currentProject == null? null : currentProject.id"
|
||||
@refresh="refresh"/>
|
||||
<test-case-export/>
|
||||
<el-input type="text" size="small"
|
||||
class="search"
|
||||
:placeholder="$t('load_test.search_by_name')"
|
||||
prefix-icon="el-icon-search"
|
||||
maxlength="60"
|
||||
v-model="condition"
|
||||
@change="search" clearable/></span>
|
||||
<ms-table-search-bar :condition.sync="condition" @change="initTableData"/>
|
||||
</span>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -94,16 +92,17 @@
|
|||
import TestCaseImport from '../components/TestCaseImport';
|
||||
import TestCaseExport from '../components/TestCaseExport';
|
||||
import MsTablePagination from '../../../../components/common/pagination/TablePagination';
|
||||
|
||||
import MsTableSearchBar from '../../../../components/common/components/MsTableSearchBar';
|
||||
import NodeBreadcrumb from '../../common/NodeBreadcrumb';
|
||||
|
||||
export default {
|
||||
name: "TestCaseList",
|
||||
components: {MsCreateBox, TestCaseImport, TestCaseExport, MsTablePagination},
|
||||
components: {MsCreateBox, TestCaseImport, TestCaseExport, MsTablePagination, NodeBreadcrumb, MsTableSearchBar},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
deletePath: "/test/case/delete",
|
||||
condition: "",
|
||||
condition: {},
|
||||
tableData: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
|
@ -113,6 +112,12 @@
|
|||
props: {
|
||||
currentProject: {
|
||||
type: Object
|
||||
},
|
||||
selectNodeIds: {
|
||||
type: Array
|
||||
},
|
||||
selectNodeNames: {
|
||||
type: Array
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
|
@ -121,18 +126,17 @@
|
|||
watch: {
|
||||
currentProject() {
|
||||
this.initTableData();
|
||||
},
|
||||
selectNodeIds() {
|
||||
this.initTableData();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initTableData(nodeIds) {
|
||||
let param = {
|
||||
name: this.condition,
|
||||
};
|
||||
param.nodeIds = nodeIds;
|
||||
|
||||
initTableData() {
|
||||
this.condition.nodeIds = this.selectNodeIds;
|
||||
if (this.currentProject) {
|
||||
param.projectId = this.currentProject.id;
|
||||
this.result = this.$post(this.buildPagePath('/test/case/list'), param, response => {
|
||||
this.condition.projectId = this.currentProject.id;
|
||||
this.result = this.$post(this.buildPagePath('/test/case/list'), this.condition, response => {
|
||||
let data = response.data;
|
||||
this.total = data.itemCount;
|
||||
this.tableData = data.listObject;
|
||||
|
@ -172,6 +176,7 @@
|
|||
});
|
||||
},
|
||||
refresh() {
|
||||
this.condition = {};
|
||||
this.$emit('refresh');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
<template>
|
||||
<el-breadcrumb separator-class="el-icon-arrow-right">
|
||||
<el-breadcrumb-item>
|
||||
<a @click="showAll">
|
||||
<i class="el-icon-s-home"></i>
|
||||
{{$t('test_track.plan_view.all_case')}}
|
||||
</a>
|
||||
</el-breadcrumb-item>
|
||||
<el-breadcrumb-item v-for="nodeName in data" :key="nodeName">{{nodeName}}</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "NodeBreadcrumb",
|
||||
data() {
|
||||
return {
|
||||
data: []
|
||||
}
|
||||
},
|
||||
props: {
|
||||
nodeNames: {
|
||||
type: Array
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
nodeNames() {
|
||||
this.filterData();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showAll() {
|
||||
this.$emit('refresh');
|
||||
},
|
||||
filterData() {
|
||||
this.data = this.nodeNames;
|
||||
if (this.data.length > 4) {
|
||||
let lastData = this.data[this.data.length - 1];
|
||||
this.data.splice(1, this.data.length);
|
||||
this.data.push('...');
|
||||
this.data.push(lastData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
|
||||
<el-dialog :title="$t('test_track.module.add_module')"
|
||||
:visible.sync="dialogFormVisible"
|
||||
width="30%">
|
||||
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="18">
|
||||
<el-form :model="form" :rules="rules">
|
||||
<el-form-item
|
||||
:label="$t('test_track.module.name')"
|
||||
:label-width="formLabelWidth"
|
||||
prop="name">
|
||||
<el-input v-model="form.name" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<template v-slot:footer>
|
||||
<ms-dialog-footer
|
||||
@cancel="dialogFormVisible = false"
|
||||
@confirm="saveNode"/>
|
||||
</template>
|
||||
|
||||
|
||||
</el-dialog>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {CURRENT_PROJECT} from '../../../../common/js/constants';
|
||||
import MsDialogFooter from '../../common/components/MsDialogFooter';
|
||||
|
||||
export default {
|
||||
components: {MsDialogFooter},
|
||||
data() {
|
||||
return {
|
||||
name: "NodeEdit",
|
||||
form: {
|
||||
name: '',
|
||||
},
|
||||
rules:{
|
||||
name :[
|
||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||
{ max: 30, message: this.$t('test_track.length_less_than') + '30', trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
type: '',
|
||||
node: {},
|
||||
formLabelWidth: '80px',
|
||||
dialogFormVisible: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(type, data) {
|
||||
this.type = type;
|
||||
this.node = data;
|
||||
this.dialogFormVisible = true;
|
||||
},
|
||||
saveNode() {
|
||||
let param = {};
|
||||
let url = this.buildParam(param);
|
||||
this.$post(url, param, () => {
|
||||
this.$message.success(this.$t('commons.save_success'));
|
||||
this.$emit('refresh');
|
||||
this.close();
|
||||
});
|
||||
},
|
||||
buildParam(param, ) {
|
||||
let url = '';
|
||||
if (this.type === 'add') {
|
||||
url = '/case/node/add';
|
||||
param.level = 1;
|
||||
if (this.node) {
|
||||
//非根节点
|
||||
param.pId = this.node.id;
|
||||
param.level = this.node.level + 1;
|
||||
}
|
||||
} else if (this.type === 'edit') {
|
||||
url = '/case/node/edit';
|
||||
param.id = this.node.id
|
||||
}
|
||||
param.name = this.form.name;
|
||||
param.label = this.form.name;
|
||||
if (localStorage.getItem(CURRENT_PROJECT)) {
|
||||
param.projectId = JSON.parse(localStorage.getItem(CURRENT_PROJECT)).id;
|
||||
}
|
||||
return url;
|
||||
},
|
||||
close() {
|
||||
this.form.name = '';
|
||||
this.dialogFormVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -3,7 +3,7 @@
|
|||
<div v-loading="result.loading">
|
||||
<el-input :placeholder="$t('test_track.module.search')" v-model="filterText"
|
||||
size="small">
|
||||
<template v-slot:append>
|
||||
<template v-if="type == 'edit'" v-slot:append>
|
||||
<el-button icon="el-icon-folder-add" @click="openEditNodeDialog('add')"></el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
|
@ -20,47 +20,37 @@
|
|||
ref="tree">
|
||||
|
||||
<template v-slot:default="{node,data}">
|
||||
|
||||
<span class="custom-tree-node father" @click="selectNode(node)">
|
||||
|
||||
<span>{{node.label}}</span>
|
||||
<el-dropdown class="node-dropdown child">
|
||||
|
||||
<el-dropdown v-if="type == 'edit'" class="node-dropdown child">
|
||||
<span class="el-dropdown-link">
|
||||
<i class="el-icon-folder-add"></i>
|
||||
</span>
|
||||
<el-dropdown-menu v-slot:default>
|
||||
<el-dropdown-item>
|
||||
<div @click="openEditNodeDialog('edit', data)">{{$t('test_track.module.rename')}}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<div @click="openEditNodeDialog('add', data)">{{$t('test_track.module.add_submodule')}}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<div @click="remove(node, data)">{{$t('commons.delete')}}</div>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<el-dropdown-menu v-slot:default>
|
||||
<el-dropdown-item>
|
||||
<div @click="openEditNodeDialog('edit', data)">{{$t('test_track.module.rename')}}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<div @click="openEditNodeDialog('add', data)">{{$t('test_track.module.add_submodule')}}</div>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item>
|
||||
<div @click="remove(node, data)">{{$t('commons.delete')}}</div>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
|
||||
</span>
|
||||
|
||||
<!--<span v-if="type == 'view'" class="custom-tree-node" @click="selectNode(node)">-->
|
||||
<!--{{node.label}}$$-->
|
||||
<!--</span>-->
|
||||
</template>
|
||||
</el-tree>
|
||||
|
||||
<el-dialog :title="$t('test_track.module.add_module')" :visible.sync="dialogFormVisible" width="500px">
|
||||
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="18">
|
||||
<el-form :model="form">
|
||||
<el-form-item :label="$t('test_track.module.name')" :label-width="formLabelWidth">
|
||||
<el-input v-model="form.name" autocomplete="off"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<template v-slot:footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">{{$t('test_track.cancel')}}</el-button>
|
||||
<el-button type="primary" @click="editNode">{{$t('test_track.confirm')}}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<node-edit ref="nodeEdit" @refresh="refreshNode"/>
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -68,10 +58,11 @@
|
|||
|
||||
<script>
|
||||
|
||||
import {CURRENT_PROJECT} from '../../../../../common/js/constants';
|
||||
import NodeEdit from './NodeEdit';
|
||||
|
||||
export default {
|
||||
name: "NodeTree",
|
||||
components: {NodeEdit},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
|
@ -80,34 +71,23 @@
|
|||
children: 'children',
|
||||
label: 'label'
|
||||
},
|
||||
form: {
|
||||
name: '',
|
||||
},
|
||||
formLabelWidth: '80px',
|
||||
dialogTableVisible: false,
|
||||
dialogFormVisible: false,
|
||||
editType: '',
|
||||
editData: {},
|
||||
treeNodes: [],
|
||||
defaultKeys: []
|
||||
// treeNodes: [],
|
||||
};
|
||||
},
|
||||
props: {
|
||||
currentProject: {
|
||||
type: Object
|
||||
type: {
|
||||
type: String,
|
||||
default: 'view'
|
||||
},
|
||||
treeNodes: {
|
||||
type: Array
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.tree.filter(val);
|
||||
},
|
||||
currentProject() {
|
||||
this.getNodeTree();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getNodeTree();
|
||||
},
|
||||
methods: {
|
||||
handleDragEnd(draggingNode, dropNode, dropType, ev) {
|
||||
let param = {};
|
||||
|
@ -148,8 +128,10 @@
|
|||
},
|
||||
selectNode(node) {
|
||||
let nodeIds = [];
|
||||
let nodeNames = [];
|
||||
this.getChildNodeId(node, nodeIds);
|
||||
this.$emit("nodeSelectEvent", nodeIds);
|
||||
this.getParentNodeName(node, nodeNames);
|
||||
this.$emit("nodeSelectEvent", nodeIds, nodeNames);
|
||||
},
|
||||
getChildNodeId(rootNode, nodeIds) {
|
||||
//递归获取所有子节点ID
|
||||
|
@ -157,69 +139,25 @@
|
|||
for (let i = 0; i < rootNode.childNodes.length; i++) {
|
||||
this.getChildNodeId(rootNode.childNodes[i], nodeIds);
|
||||
}
|
||||
return nodeIds;
|
||||
},
|
||||
getParentNodeName(rootNode, nodeNames) {
|
||||
if (rootNode.parent && rootNode.parent.id != 0) {
|
||||
this.getParentNodeName(rootNode.parent, nodeNames)
|
||||
}
|
||||
if (rootNode.data.name && rootNode.data.name != '') {
|
||||
nodeNames.push(rootNode.data.name);
|
||||
}
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data.label.indexOf(value) !== -1;
|
||||
},
|
||||
editNode() {
|
||||
this.saveNode(this.editType, this.editData);
|
||||
this.dialogFormVisible = false;
|
||||
},
|
||||
openEditNodeDialog(type, data) {
|
||||
this.editType = type;
|
||||
this.editData = data;
|
||||
this.dialogFormVisible = true;
|
||||
},
|
||||
getNodeTree() {
|
||||
if (this.currentProject) {
|
||||
let projectId = this.currentProject.id;
|
||||
this.result = this.$get("/case/node/list/" + projectId, response => {
|
||||
this.treeNodes = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
saveNode(type, pNode) {
|
||||
let param = {};
|
||||
let url = '';
|
||||
|
||||
if (type === 'add') {
|
||||
url = '/case/node/add';
|
||||
param.level = 1;
|
||||
if (pNode) {
|
||||
//非根节点
|
||||
param.pId = pNode.id;
|
||||
param.level = pNode.level + 1;
|
||||
}
|
||||
} else if (type === 'edit') {
|
||||
url = '/case/node/edit';
|
||||
param.id = this.editData.id
|
||||
}
|
||||
|
||||
param.name = this.form.name;
|
||||
param.label = this.form.name;
|
||||
|
||||
if (localStorage.getItem(CURRENT_PROJECT)) {
|
||||
param.projectId = JSON.parse(localStorage.getItem(CURRENT_PROJECT)).id;
|
||||
}
|
||||
|
||||
this.$post(url, param, response => {
|
||||
if (type === 'edit') {
|
||||
this.editData.label = param.label;
|
||||
}
|
||||
if (type === 'add') {
|
||||
param.id = response.data;
|
||||
if (pNode) {
|
||||
this.$refs.tree.append(param, pNode);
|
||||
} else {
|
||||
this.treeNodes.push(param);
|
||||
}
|
||||
}
|
||||
this.$message.success(this.$t('commons.save_success'));
|
||||
});
|
||||
this.form.name = '';
|
||||
this.$refs.nodeEdit.open(type, data);
|
||||
},
|
||||
refreshNode() {
|
||||
this.$emit('refresh');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -105,8 +105,10 @@
|
|||
},
|
||||
selectNode(node) {
|
||||
let nodeIds = [];
|
||||
let nodeNames = [];
|
||||
this.getChildNodeId(node, nodeIds);
|
||||
this.$emit("nodeSelectEvent", nodeIds);
|
||||
this.getParentNodeName(node, nodeNames);
|
||||
this.$emit("nodeSelectEvent", nodeIds, nodeNames);
|
||||
},
|
||||
getChildNodeId(rootNode, nodeIds) {
|
||||
//递归获取所有子节点ID
|
||||
|
@ -114,7 +116,14 @@
|
|||
for (let i = 0; i < rootNode.childNodes.length; i++){
|
||||
this.getChildNodeId(rootNode.childNodes[i], nodeIds);
|
||||
}
|
||||
return nodeIds;
|
||||
},
|
||||
getParentNodeName(rootNode, nodeNames) {
|
||||
if (rootNode.parent && rootNode.parent.id != 0) {
|
||||
this.getParentNodeName(rootNode.parent, nodeNames)
|
||||
}
|
||||
if (rootNode.data.name && rootNode.data.name != '') {
|
||||
nodeNames.push(rootNode.data.name);
|
||||
}
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
|
@ -6,16 +6,14 @@
|
|||
:data="testPlans"
|
||||
:current-data="currentPlan"
|
||||
:title="$t('test_track.plan_view.plan')"
|
||||
@dataChange="changePlan">
|
||||
</select-menu>
|
||||
|
||||
<plan-node-tree
|
||||
class="node-tree"
|
||||
:plan-id="planId"
|
||||
@nodeSelectEvent="getPlanCases"
|
||||
ref="tree">
|
||||
</plan-node-tree>
|
||||
@dataChange="changePlan"/>
|
||||
|
||||
<node-tree class="node-tree"
|
||||
v-loading="result.loading"
|
||||
@nodeSelectEvent="nodeChange"
|
||||
@refresh="refresh"
|
||||
:tree-nodes="treeNodes"
|
||||
ref="nodeTree"/>
|
||||
</el-aside>
|
||||
|
||||
<el-main>
|
||||
|
@ -23,33 +21,38 @@
|
|||
@openTestCaseRelevanceDialog="openTestCaseRelevanceDialog"
|
||||
@refresh="refresh"
|
||||
:plan-id="planId"
|
||||
ref="testCasePlanList"></test-plan-test-case-list>
|
||||
:select-node-ids="selectNodeIds"
|
||||
:select-node-names="selectNodeNames"
|
||||
ref="testCasePlanList"/>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
<test-case-relevance
|
||||
@refresh="refresh"
|
||||
:plan-id="planId"
|
||||
ref="testCaseRelevance">
|
||||
</test-case-relevance>
|
||||
ref="testCaseRelevance"/>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import PlanNodeTree from "./components/PlanNodeTree";
|
||||
import NodeTree from "../common/NodeTree";
|
||||
import TestPlanTestCaseList from "./components/TestPlanTestCaseList";
|
||||
import TestCaseRelevance from "./components/TestCaseRelevance";
|
||||
import SelectMenu from "../common/SelectMenu";
|
||||
|
||||
export default {
|
||||
name: "TestPlanView",
|
||||
components: {PlanNodeTree, TestPlanTestCaseList, TestCaseRelevance, SelectMenu},
|
||||
components: {NodeTree, TestPlanTestCaseList, TestCaseRelevance, SelectMenu},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
testPlans: [],
|
||||
currentPlan: {}
|
||||
currentPlan: {},
|
||||
selectNodeIds: [],
|
||||
selectNodeNames: [],
|
||||
treeNodes: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -57,21 +60,23 @@
|
|||
return this.$route.params.planId;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getTestPlans();
|
||||
mounted() {
|
||||
this.initData();
|
||||
},
|
||||
watch: {
|
||||
planId() {
|
||||
this.getTestPlans();
|
||||
this.initData();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
refresh() {
|
||||
this.getPlanCases();
|
||||
this.$refs.tree.initTree();
|
||||
this.selectNodeIds = [];
|
||||
this.selectNodeNames = [];
|
||||
this.getNodeTreeByPlanId();
|
||||
},
|
||||
getPlanCases(nodeIds) {
|
||||
this.$refs.testCasePlanList.initTableData(nodeIds);
|
||||
initData() {
|
||||
this.getTestPlans();
|
||||
this.getNodeTreeByPlanId();
|
||||
},
|
||||
openTestCaseRelevanceDialog() {
|
||||
this.$refs.testCaseRelevance.openTestCaseRelevanceDialog();
|
||||
|
@ -86,9 +91,20 @@
|
|||
});
|
||||
});
|
||||
},
|
||||
nodeChange(nodeIds, nodeNames) {
|
||||
this.selectNodeIds = nodeIds;
|
||||
this.selectNodeNames = nodeNames;
|
||||
},
|
||||
changePlan(plan) {
|
||||
this.currentPlan = plan;
|
||||
this.$router.push('/track/plan/view/' + plan.id);
|
||||
},
|
||||
getNodeTreeByPlanId() {
|
||||
if(this.planId){
|
||||
this.result = this.$get("/case/node/list/plan/" + this.planId, response => {
|
||||
this.treeNodes = response.data;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,8 +133,4 @@
|
|||
padding: 15px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
/*background: white;*/
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -9,12 +9,11 @@
|
|||
|
||||
<el-container class="main-content">
|
||||
<el-aside class="node-tree" width="250px">
|
||||
<plan-node-tree
|
||||
:tree-nodes="treeNodes"
|
||||
:plan-id="planId"
|
||||
:showAll=true
|
||||
@nodeSelectEvent="getCaseNameByNodeIds"
|
||||
ref="tree"></plan-node-tree>
|
||||
<node-tree class="node-tree"
|
||||
@nodeSelectEvent="nodeChange"
|
||||
@refresh="refresh"
|
||||
:tree-nodes="treeNodes"
|
||||
ref="nodeTree"/>
|
||||
</el-aside>
|
||||
|
||||
<el-container>
|
||||
|
@ -45,32 +44,22 @@
|
|||
</el-container>
|
||||
|
||||
<template v-slot:footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button
|
||||
@click="dialogFormVisible = false">
|
||||
{{$t('test_track.cancel')}}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="saveCaseRelevance">
|
||||
{{$t('test_track.confirm')}}
|
||||
</el-button>
|
||||
</div>
|
||||
<ms-dialog-footer @cancel="dialogFormVisible = false" @confirm="saveCaseRelevance"/>
|
||||
</template>
|
||||
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import PlanNodeTree from './PlanNodeTree';
|
||||
import NodeTree from '../../common/NodeTree';
|
||||
import MsDialogFooter from '../../../common/components/MsDialogFooter'
|
||||
|
||||
export default {
|
||||
export default {
|
||||
name: "TestCaseRelevance",
|
||||
components: {PlanNodeTree},
|
||||
components: {NodeTree, MsDialogFooter},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
|
@ -78,7 +67,9 @@
|
|||
isCheckAll: false,
|
||||
testCases: [],
|
||||
selectIds: new Set(),
|
||||
treeNodes: []
|
||||
treeNodes: [],
|
||||
selectNodeIds: [],
|
||||
selectNodeNames: []
|
||||
};
|
||||
},
|
||||
props: {
|
||||
|
@ -88,12 +79,15 @@
|
|||
},
|
||||
watch: {
|
||||
planId() {
|
||||
this.initData();
|
||||
},
|
||||
selectNodeIds() {
|
||||
this.getCaseNames();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openTestCaseRelevanceDialog() {
|
||||
this.getCaseNames();
|
||||
this.initData();
|
||||
this.dialogFormVisible = true;
|
||||
},
|
||||
saveCaseRelevance(){
|
||||
|
@ -107,13 +101,13 @@
|
|||
this.$emit('refresh');
|
||||
});
|
||||
},
|
||||
getCaseNames(nodeIds) {
|
||||
getCaseNames() {
|
||||
let param = {};
|
||||
if (this.planId) {
|
||||
param.planId = this.planId;
|
||||
}
|
||||
if (nodeIds && nodeIds.length > 0){
|
||||
param.nodeIds = nodeIds;
|
||||
if (this.selectNodeIds && this.selectNodeIds.length > 0){
|
||||
param.nodeIds = this.selectNodeIds;
|
||||
}
|
||||
this.result = this.$post('/test/case/name', param, response => {
|
||||
this.testCases = response.data;
|
||||
|
@ -122,10 +116,6 @@
|
|||
});
|
||||
});
|
||||
},
|
||||
getCaseNameByNodeIds(nodeIds) {
|
||||
this.dialogFormVisible = true;
|
||||
this.getCaseNames(nodeIds);
|
||||
},
|
||||
handleSelectAll(selection) {
|
||||
if(selection.length > 0){
|
||||
this.testCases.forEach(item => {
|
||||
|
@ -142,8 +132,28 @@
|
|||
this.selectIds.add(row.id);
|
||||
}
|
||||
},
|
||||
nodeChange(nodeIds, nodeNames) {
|
||||
this.selectNodeIds = nodeIds;
|
||||
this.selectNodeNames = nodeNames;
|
||||
},
|
||||
initData() {
|
||||
this.getCaseNames();
|
||||
this.getAllNodeTreeByPlanId();
|
||||
},
|
||||
refresh() {
|
||||
this.close();
|
||||
},
|
||||
getAllNodeTreeByPlanId() {
|
||||
if (this.planId) {
|
||||
this.result = this.$get("/case/node/list/all/plan/" + this.planId, response => {
|
||||
this.treeNodes = response.data;
|
||||
});
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.selectIds.clear();
|
||||
this.selectNodeIds = [];
|
||||
this.selectNodeNames = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,158 +1,167 @@
|
|||
<template>
|
||||
|
||||
|
||||
<el-drawer
|
||||
:before-close="handleClose"
|
||||
:visible.sync="showDialog"
|
||||
:with-header="false"
|
||||
size="100%"
|
||||
ref="drawer">
|
||||
ref="drawer"
|
||||
v-loading="result.loading">
|
||||
|
||||
<template v-slot:default="scope">
|
||||
<template v-slot:default="scope">
|
||||
<div class="container">
|
||||
|
||||
<el-header>
|
||||
<el-scrollbar>
|
||||
|
||||
<el-row type="flex" class="head-bar">
|
||||
<el-header>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-button plain size="mini"
|
||||
icon="el-icon-back"
|
||||
@click="cancel">{{$t('test_track.return')}}</el-button>
|
||||
</el-col>
|
||||
<el-row type="flex" class="head-bar">
|
||||
|
||||
<el-col :span="12" class="head-right">
|
||||
<span class="head-right-tip" v-if="index + 1 == tableData.length">
|
||||
{{$t('test_track.plan_view.pre_case')}} : {{tableData ? tableData[index - 1].name : ''}}
|
||||
</span>
|
||||
<span class="head-right-tip" v-if="index + 1 < tableData.length">
|
||||
{{$t('test_track.plan_view.next_case')}} : {{tableData ? tableData[index + 1].name : ''}}
|
||||
</span>
|
||||
<el-col :span="12">
|
||||
<el-button plain size="mini"
|
||||
icon="el-icon-back"
|
||||
@click="cancel">{{$t('test_track.return')}}</el-button>
|
||||
</el-col>
|
||||
|
||||
<el-button plain size="mini" icon="el-icon-arrow-up"
|
||||
:disabled="index + 1 <= 1"
|
||||
@click="handlePre()"/>
|
||||
<span> {{index + 1}}/{{tableData.length}} </span>
|
||||
<el-button plain size="mini" icon="el-icon-arrow-down"
|
||||
:disabled="index + 1 >= tableData.length"
|
||||
@click="handleNext()"/>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
<el-col :span="12" class="head-right">
|
||||
<span class="head-right-tip" v-if="index + 1 == testCases.length">
|
||||
{{$t('test_track.plan_view.pre_case')}} : {{testCases[index - 1] ? testCases[index - 1].name : ''}}
|
||||
</span>
|
||||
<span class="head-right-tip" v-if="index + 1 != testCases.length">
|
||||
{{$t('test_track.plan_view.next_case')}} : {{testCases[index + 1] ? testCases[index + 1].name : ''}}
|
||||
</span>
|
||||
|
||||
<el-button type="primary" size="mini" @click="saveCase">{{$t('test_track.save')}}</el-button>
|
||||
</el-col>
|
||||
<el-button plain size="mini" icon="el-icon-arrow-up"
|
||||
:disabled="index + 1 <= 1"
|
||||
@click="handlePre()"/>
|
||||
<span> {{index + 1}}/{{testCases.length}} </span>
|
||||
<el-button plain size="mini" icon="el-icon-arrow-down"
|
||||
:disabled="index + 1 >= testCases.length"
|
||||
@click="handleNext()"/>
|
||||
<el-divider direction="vertical"></el-divider>
|
||||
|
||||
</el-row>
|
||||
<el-button type="primary" size="mini" @click="saveCase">{{$t('test_track.save')}}</el-button>
|
||||
</el-col>
|
||||
|
||||
<el-row style="margin-top: 0px;">
|
||||
<el-col>
|
||||
<el-divider content-position="left">{{testCase.name}}</el-divider>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-row>
|
||||
|
||||
</el-header>
|
||||
<el-row style="margin-top: 0px;">
|
||||
<el-col>
|
||||
<el-divider content-position="left">{{testCase.name}}</el-divider>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<div class="case_container">
|
||||
<el-row >
|
||||
<el-col :span="4" :offset="1">
|
||||
<span class="cast_label">{{$t('test_track.case.priority')}}:</span>
|
||||
<span class="cast_item">{{testCase.priority}}</span>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<span class="cast_label">{{$t('test_track.case.case_type')}}:</span>
|
||||
<span class="cast_item" v-if="testCase.type == 'functional'">{{$t('commons.functional')}}</span>
|
||||
<span class="cast_item" v-if="testCase.type == 'performance'">{{$t('commons.performance')}}</span>
|
||||
<span class="cast_item" v-if="testCase.type == 'api'">{{$t('commons.api')}}</span>
|
||||
</el-col>
|
||||
<el-col :span="13">
|
||||
<test-plan-test-case-status-button class="status-button"
|
||||
@statusChange="statusChange"
|
||||
:status="testCase.status"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-header>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="4" :offset="1">
|
||||
<span class="cast_label">{{$t('test_track.case.method')}}:</span>
|
||||
<span v-if="testCase.method == 'manual'">{{$t('test_track.case.manual')}}</span>
|
||||
<span v-if="testCase.method == 'auto'">{{$t('test_track.case.auto')}}</span>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<span class="cast_label">{{$t('test_track.case.module')}}:</span>
|
||||
<span class="cast_item">{{testCase.nodePath}}</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="case_container">
|
||||
<el-row >
|
||||
<el-col :span="4" :offset="1">
|
||||
<span class="cast_label">{{$t('test_track.case.priority')}}:</span>
|
||||
<span class="cast_item">{{testCase.priority}}</span>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<span class="cast_label">{{$t('test_track.case.case_type')}}:</span>
|
||||
<span class="cast_item" v-if="testCase.type == 'functional'">{{$t('commons.functional')}}</span>
|
||||
<span class="cast_item" v-if="testCase.type == 'performance'">{{$t('commons.performance')}}</span>
|
||||
<span class="cast_item" v-if="testCase.type == 'api'">{{$t('commons.api')}}</span>
|
||||
</el-col>
|
||||
<el-col :span="13">
|
||||
<test-plan-test-case-status-button class="status-button"
|
||||
@statusChange="statusChange"
|
||||
:status="testCase.status"/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="20" :offset="1">
|
||||
<div>
|
||||
<span class="cast_label">{{$t('test_track.case.steps')}}:</span>
|
||||
</div>
|
||||
<el-table
|
||||
:data="testCase.steptResults"
|
||||
class="tb-edit"
|
||||
size="mini"
|
||||
height="250px"
|
||||
:border="true"
|
||||
:default-sort = "{prop: 'num', order: 'ascending'}"
|
||||
highlight-current-row>
|
||||
<el-table-column :label="$t('test_track.case.number')" prop="num" min-width="5%"></el-table-column>
|
||||
<el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="29%">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{scope.row.desc}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('test_track.case.expected_results')" prop="result" min-width="28%">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{scope.row.result}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('test_track.plan_view.actual_result')" min-width="29%">
|
||||
<template v-slot:default="scope">
|
||||
<el-input
|
||||
<el-row>
|
||||
<el-col :span="4" :offset="1">
|
||||
<span class="cast_label">{{$t('test_track.case.method')}}:</span>
|
||||
<span v-if="testCase.method == 'manual'">{{$t('test_track.case.manual')}}</span>
|
||||
<span v-if="testCase.method == 'auto'">{{$t('test_track.case.auto')}}</span>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<span class="cast_label">{{$t('test_track.case.module')}}:</span>
|
||||
<span class="cast_item">{{testCase.nodePath}}</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="20" :offset="1">
|
||||
<div>
|
||||
<span class="cast_label">{{$t('test_track.case.steps')}}:</span>
|
||||
</div>
|
||||
<el-table
|
||||
:data="testCase.steptResults"
|
||||
class="tb-edit"
|
||||
size="mini"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
v-model="scope.row.actualResult"
|
||||
:placeholder="$t('commons.input_content')"
|
||||
clearable></el-input>
|
||||
<span>{{scope.row.actualResult}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('test_track.plan_view.step_result')" min-width="9%">
|
||||
<template v-slot:default="scope">
|
||||
<el-select
|
||||
v-model="scope.row.executeResult"
|
||||
size="mini">
|
||||
<el-option :label="$t('test_track.plan_view.pass')" value="Pass" style="color: #7ebf50;"></el-option>
|
||||
<el-option :label="$t('test_track.plan_view.failure')" value="Failure" style="color: #e57471;"></el-option>
|
||||
<el-option :label="$t('test_track.plan_view.blocking')" value="Blocking" style="color: #dda451;"></el-option>
|
||||
<el-option :label="$t('test_track.plan_view.skip')" value="Skip" style="color: #919399;"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-col>
|
||||
</el-row>
|
||||
:border="true"
|
||||
:default-sort = "{prop: 'num', order: 'ascending'}"
|
||||
highlight-current-row>
|
||||
<el-table-column :label="$t('test_track.case.number')" prop="num" min-width="5%"></el-table-column>
|
||||
<el-table-column :label="$t('test_track.case.step_desc')" prop="desc" min-width="29%">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{scope.row.desc}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('test_track.case.expected_results')" prop="result" min-width="28%">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{scope.row.result}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('test_track.plan_view.actual_result')" min-width="29%">
|
||||
<template v-slot:default="scope">
|
||||
<el-input
|
||||
size="mini"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
v-model="scope.row.actualResult"
|
||||
:placeholder="$t('commons.input_content')"
|
||||
clearable></el-input>
|
||||
<span>{{scope.row.actualResult}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('test_track.plan_view.step_result')" min-width="9%">
|
||||
<template v-slot:default="scope">
|
||||
<el-select
|
||||
v-model="scope.row.executeResult"
|
||||
size="mini">
|
||||
<el-option :label="$t('test_track.plan_view.pass')" value="Pass" style="color: #7ebf50;"></el-option>
|
||||
<el-option :label="$t('test_track.plan_view.failure')" value="Failure" style="color: #e57471;"></el-option>
|
||||
<el-option :label="$t('test_track.plan_view.blocking')" value="Blocking" style="color: #dda451;"></el-option>
|
||||
<el-option :label="$t('test_track.plan_view.skip')" value="Skip" style="color: #919399;"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row>
|
||||
<el-col :span="15" :offset="1">
|
||||
<div>
|
||||
<span class="cast_label">{{$t('commons.remark')}}:</span>
|
||||
<span v-if="testCase.remark == null || testCase.remark == ''" style="color: darkgrey">{{$t('commons.not_filled')}}</span>
|
||||
<el-row>
|
||||
<el-col :span="15" :offset="1">
|
||||
<div>
|
||||
<span class="cast_label">{{$t('commons.remark')}}:</span>
|
||||
<span v-if="testCase.remark == null || testCase.remark == ''" style="color: darkgrey">{{$t('commons.not_filled')}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<el-input :rows="3"
|
||||
type="textarea"
|
||||
v-if="testCase.remark"
|
||||
disabled
|
||||
v-model="testCase.remark"></el-input>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div>
|
||||
<el-input :rows="3"
|
||||
type="textarea"
|
||||
v-if="testCase.remark"
|
||||
disabled
|
||||
v-model="testCase.remark"></el-input>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
</el-scrollbar>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -163,17 +172,19 @@
|
|||
components: {TestPlanTestCaseStatusButton},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
showDialog: false,
|
||||
testCase: {},
|
||||
index: 0
|
||||
index: 0,
|
||||
testCases: []
|
||||
};
|
||||
},
|
||||
props: {
|
||||
tableData: {
|
||||
type: Array
|
||||
},
|
||||
total: {
|
||||
type: Number
|
||||
},
|
||||
searchParam: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -213,7 +224,7 @@
|
|||
this.getTestCase(this.index);
|
||||
},
|
||||
getTestCase(index) {
|
||||
let testCase = this.tableData[index];
|
||||
let testCase = this.testCases[index];
|
||||
let item = {};
|
||||
Object.assign(item, testCase);
|
||||
item.results = JSON.parse(item.results);
|
||||
|
@ -227,6 +238,22 @@
|
|||
item.steptResults.push(item.steps[i]);
|
||||
}
|
||||
this.testCase = item;
|
||||
},
|
||||
openTestCaseEdit(testCase) {
|
||||
this.showDialog = true;
|
||||
this.initData(testCase);
|
||||
|
||||
},
|
||||
initData(testCase) {
|
||||
this.result = this.$post('/test/plan/case/list/all', this.searchParam, response => {
|
||||
this.testCases = response.data;
|
||||
for (let i = 0; i < this.testCases.length; i++) {
|
||||
if (this.testCases[i].id === testCase.id) {
|
||||
this.index = i;
|
||||
this.getTestCase(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -265,12 +292,20 @@
|
|||
float: right;
|
||||
}
|
||||
|
||||
.head-bar {
|
||||
margin-top: 1%;
|
||||
}
|
||||
|
||||
.head-right-tip {
|
||||
color: darkgrey;
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.case_container > .el-row{
|
||||
margin-top: 1%;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -5,13 +5,18 @@
|
|||
<template v-slot:header>
|
||||
<div>
|
||||
<el-row type="flex" justify="space-between" align="middle">
|
||||
<span class="title">{{$t('test_track.case.test_case')}}
|
||||
<span class="title">
|
||||
<node-breadcrumb
|
||||
:node-names="selectNodeNames"
|
||||
@refresh="refresh"/>
|
||||
|
||||
<ms-tip-button v-if="!showMyTestCase"
|
||||
:tip="$t('test_track.plan_view.my_case')"
|
||||
icon="el-icon-s-custom" @click="searchMyTestCase"/>
|
||||
<ms-tip-button v-if="showMyTestCase"
|
||||
:tip="$t('test_track.plan_view.all_case')"
|
||||
icon="el-icon-files" @click="searchMyTestCase"/></span>
|
||||
icon="el-icon-files" @click="searchMyTestCase"/>
|
||||
</span>
|
||||
|
||||
<span class="operate-button">
|
||||
<el-button icon="el-icon-connection" size="small" round
|
||||
|
@ -23,23 +28,12 @@
|
|||
<el-button icon="el-icon-user" size="small" round
|
||||
@click="handleBatch('executor')" >{{$t('test_track.plan_view.change_executor')}}</el-button>
|
||||
|
||||
<el-input type="text" size="small"
|
||||
class="search"
|
||||
:placeholder="$t('load_test.search_by_name')"
|
||||
prefix-icon="el-icon-search"
|
||||
maxlength="60"
|
||||
v-model="condition.name" @change="search" clearable/>
|
||||
<ms-table-search-bar :condition.sync="condition" @change="initTableData"/>
|
||||
</span>
|
||||
</el-row>
|
||||
|
||||
<executor-edit
|
||||
ref="executorEdit"
|
||||
:select-ids="selectIds"
|
||||
@refresh="initTableData"/>
|
||||
<status-edit
|
||||
ref="statusEdit"
|
||||
:select-ids="selectIds"
|
||||
@refresh="initTableData"/>
|
||||
<executor-edit ref="executorEdit" :select-ids="selectIds" @refresh="refresh"/>
|
||||
<status-edit ref="statusEdit" :select-ids="selectIds" @refresh="refresh"/>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
@ -154,25 +148,29 @@
|
|||
|
||||
<test-plan-test-case-edit
|
||||
ref="testPlanTestCaseEdit"
|
||||
:table-data="tableData"
|
||||
@refresh="initTableData"/>
|
||||
:search-param="condition"
|
||||
@refresh="refresh"/>
|
||||
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PlanNodeTree from './PlanNodeTree';
|
||||
import PlanNodeTree from '../../common/PlanNodeTree';
|
||||
import ExecutorEdit from './ExecutorEdit';
|
||||
import StatusEdit from './StatusEdit';
|
||||
import TestPlanTestCaseEdit from "../components/TestPlanTestCaseEdit";
|
||||
import MsTipButton from '../../../../components/common/components/MsTipButton';
|
||||
import MsTablePagination from '../../../../components/common/pagination/TablePagination';
|
||||
import MsTableSearchBar from '../../../../components/common/components/MsTableSearchBar';
|
||||
import NodeBreadcrumb from '../../common/NodeBreadcrumb';
|
||||
|
||||
import {TokenKey} from '../../../../../common/js/constants';
|
||||
|
||||
export default {
|
||||
name: "TestPlanTestCaseList",
|
||||
components: {PlanNodeTree, StatusEdit, ExecutorEdit, MsTipButton, MsTablePagination, TestPlanTestCaseEdit},
|
||||
components: {PlanNodeTree, StatusEdit, ExecutorEdit, MsTipButton, MsTablePagination,
|
||||
TestPlanTestCaseEdit, MsTableSearchBar, NodeBreadcrumb},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
|
@ -183,37 +181,47 @@
|
|||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
total: 0,
|
||||
currentDataIndex: 0,
|
||||
selectIds: new Set(),
|
||||
selectIds: new Set()
|
||||
}
|
||||
},
|
||||
props:{
|
||||
planId: {
|
||||
type: String
|
||||
},
|
||||
selectNodeIds: {
|
||||
type: Array
|
||||
},
|
||||
selectNodeNames: {
|
||||
type: Array
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
planId() {
|
||||
this.initTableData();
|
||||
},
|
||||
selectNodeIds() {
|
||||
this.search();
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
this.initTableData();
|
||||
},
|
||||
methods: {
|
||||
initTableData(nodeIds) {
|
||||
initTableData() {
|
||||
if (this.planId) {
|
||||
let param = {};
|
||||
Object.assign(param, this.condition);
|
||||
param.nodeIds = nodeIds;
|
||||
param.planId = this.planId;
|
||||
this.result = this.$post(this.buildPagePath('/test/plan/case/list'), param, response => {
|
||||
this.condition.planId = this.planId;
|
||||
this.condition.nodeIds = this.selectNodeIds;
|
||||
this.result = this.$post(this.buildPagePath('/test/plan/case/list'), this.condition, response => {
|
||||
let data = response.data;
|
||||
this.total = data.itemCount;
|
||||
this.tableData = data.listObject;
|
||||
});
|
||||
}
|
||||
},
|
||||
refresh() {
|
||||
this.condition = {};
|
||||
this.$emit('refresh');
|
||||
},
|
||||
search() {
|
||||
this.initTableData();
|
||||
},
|
||||
|
@ -221,10 +229,7 @@
|
|||
return path + "/" + this.currentPage + "/" + this.pageSize;
|
||||
},
|
||||
handleEdit(testCase, index) {
|
||||
this.currentDataIndex = index;
|
||||
this.$refs.testPlanTestCaseEdit.index = index;
|
||||
this.$refs.testPlanTestCaseEdit.getTestCase(index);
|
||||
this.$refs.testPlanTestCaseEdit.showDialog = true;
|
||||
this.$refs.testPlanTestCaseEdit.openTestCaseEdit(testCase);
|
||||
},
|
||||
handleDelete(testCase) {
|
||||
this.$alert(this.$t('test_track.plan_view.confirm_cancel_relevance') + ' ' + testCase.name + " ?", '', {
|
||||
|
@ -239,7 +244,6 @@
|
|||
_handleDelete(testCase) {
|
||||
let testCaseId = testCase.id;
|
||||
this.$post('/test/plan/case/delete/' + testCaseId, {}, () => {
|
||||
this.initTableData();
|
||||
this.$emit("refresh");
|
||||
this.$message({
|
||||
message: this.$t('commons.delete_success'),
|
||||
|
@ -299,5 +303,8 @@
|
|||
float: right;
|
||||
}
|
||||
|
||||
.el-breadcrumb {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -46,7 +46,8 @@ export default {
|
|||
'refresh': 'Refresh',
|
||||
'remark': 'Remark',
|
||||
'delete': 'Delete',
|
||||
'not_filled': 'Not filled'
|
||||
'not_filled': 'Not filled',
|
||||
'search_by_name': 'Search by name',
|
||||
},
|
||||
workspace: {
|
||||
'create': 'Create Workspace',
|
||||
|
|
|
@ -48,6 +48,7 @@ export default {
|
|||
'delete': '删除',
|
||||
'not_filled': '未填写',
|
||||
'please_select': '请选择',
|
||||
'search_by_name': '根据名称搜索',
|
||||
},
|
||||
workspace: {
|
||||
'create': '创建工作空间',
|
||||
|
|
Loading…
Reference in New Issue