diff --git a/backend/src/main/java/io/metersphere/controller/ReportController.java b/backend/src/main/java/io/metersphere/controller/ReportController.java index 65d435747b..4332b4f4c8 100644 --- a/backend/src/main/java/io/metersphere/controller/ReportController.java +++ b/backend/src/main/java/io/metersphere/controller/ReportController.java @@ -78,12 +78,12 @@ public class ReportController { } @GetMapping("/content/load_chart/{reportId}") - public ChartsData getLoadChartData(@PathVariable String reportId) { + public List getLoadChartData(@PathVariable String reportId) { return reportService.getLoadChartData(reportId); } @GetMapping("/content/res_chart/{reportId}") - public ChartsData getResponseTimeChartData(@PathVariable String reportId) { + public List getResponseTimeChartData(@PathVariable String reportId) { return reportService.getResponseTimeChartData(reportId); } diff --git a/backend/src/main/java/io/metersphere/report/JtlResolver.java b/backend/src/main/java/io/metersphere/report/JtlResolver.java index cbc72fbb86..4ff52f0dd3 100644 --- a/backend/src/main/java/io/metersphere/report/JtlResolver.java +++ b/backend/src/main/java/io/metersphere/report/JtlResolver.java @@ -1,6 +1,5 @@ package io.metersphere.report; -import com.alibaba.fastjson.JSONObject; import com.opencsv.bean.CsvToBean; import com.opencsv.bean.CsvToBeanBuilder; import com.opencsv.bean.HeaderColumnNameMappingStrategy; @@ -10,6 +9,7 @@ import io.metersphere.report.dto.RequestStatisticsDTO; import org.apache.commons.lang3.StringUtils; import java.io.Reader; import java.io.StringReader; +import java.math.BigDecimal; import java.text.DecimalFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -312,18 +312,10 @@ public class JtlResolver { } - public static ChartsData getLoadChartData(String jtlString) { - ChartsData data = new ChartsData(); + public static List getLoadChartData(String jtlString) { + List chartsDataList = new ArrayList<>(); List totalMetricList = JtlResolver.resolver(jtlString); - List users = new ArrayList<>(); - List hits = new ArrayList<>(); - List errors = new ArrayList<>(); - List timeList = new ArrayList<>(); - Map resultMap = new HashMap<>(5); - - DecimalFormat decimalFormat = new DecimalFormat("0.0"); - if (totalMetricList != null) { for (Metric metric : totalMetricList) { metric.setTimestamp(stampToDate(metric.getTimestamp())); @@ -331,7 +323,6 @@ public class JtlResolver { } Map> collect = Objects.requireNonNull(totalMetricList).stream().collect(Collectors.groupingBy(Metric::getTimestamp)); List>> entries = new ArrayList<>(collect.entrySet()); - entries.sort(JtlResolver::sortByDate); for (Map.Entry> entry : entries) { int failSize = 0; @@ -345,31 +336,38 @@ public class JtlResolver { } } + String timeStamp = ""; try { - timeList.add(formatDate(entry.getKey())); + timeStamp = formatDate(entry.getKey()); } catch (ParseException e) { e.printStackTrace(); } - hits.add(decimalFormat.format(metrics.size() * 1.0 / maxUsers)); - users.add(String.valueOf(maxUsers)); - errors.add(String.valueOf(failSize)); + ChartsData chartsData = new ChartsData(); + chartsData.setxAxis(timeStamp); + chartsData.setGroupName("hits"); + chartsData.setyAxis(new BigDecimal(metrics.size() * 1.0 / maxUsers)); + chartsDataList.add(chartsData); + + chartsData = new ChartsData(); + chartsData.setxAxis(timeStamp); + chartsData.setGroupName("users"); + chartsData.setyAxis(new BigDecimal(maxUsers)); + chartsDataList.add(chartsData); + + chartsData = new ChartsData(); + chartsData.setxAxis(timeStamp); + chartsData.setGroupName("errors"); + chartsData.setyAxis(new BigDecimal(failSize)); + chartsDataList.add(chartsData); } - resultMap.put("users", users); - resultMap.put("hits", hits); - resultMap.put("errors", errors); - - JSONObject serices = new JSONObject(resultMap); - data.setxAxis(String.join(",", timeList)); - data.setSerices(serices.toString()); - - return data; + return chartsDataList; } - public static ChartsData getResponseTimeChartData(String jtlString) { - ChartsData chartsData = new ChartsData(); + public static List getResponseTimeChartData(String jtlString) { + List chartsDataList = new ArrayList<>(); List totalMetricList = JtlResolver.resolver(jtlString); totalMetricList.forEach(metric -> { @@ -378,35 +376,34 @@ public class JtlResolver { Map> metricMap = totalMetricList.stream().collect(Collectors.groupingBy(Metric::getTimestamp)); List>> entries = new ArrayList<>(metricMap.entrySet()); - entries.sort(JtlResolver::sortByDate); - - List resTimeList = new ArrayList<>(); - List users = new ArrayList<>(); - List timestampList = new ArrayList<>(); for (Map.Entry> entry : entries) { List metricList = entry.getValue(); Map> metricsMap = metricList.stream().collect(Collectors.groupingBy(Metric::getThreadName)); int maxUsers = metricsMap.size(); int sumElapsedTime = metricList.stream().mapToInt(metric -> Integer.parseInt(metric.getElapsed())).sum(); - + String timeStamp = ""; try { - timestampList.add(formatDate(entry.getKey())); + timeStamp = formatDate(entry.getKey()); } catch (ParseException e) { e.printStackTrace(); } - users.add(String.valueOf(maxUsers)); - resTimeList.add(String.valueOf(sumElapsedTime / metricList.size())); + ChartsData chartsData = new ChartsData(); + chartsData.setxAxis(timeStamp); + chartsData.setGroupName("users"); + chartsData.setyAxis(new BigDecimal(maxUsers)); + chartsDataList.add(chartsData); + + ChartsData chartsData2 = new ChartsData(); + chartsData2.setxAxis(timeStamp); + chartsData2.setGroupName("responseTime"); + chartsData2.setyAxis(new BigDecimal(sumElapsedTime * 1.0 / metricList.size())); + chartsDataList.add(chartsData2); + } - Map resultMap = new HashMap<>(2); - resultMap.put("users", users); - resultMap.put("resTime", resTimeList); - JSONObject serices = new JSONObject(resultMap); - chartsData.setxAxis(String.join(",", timestampList)); - chartsData.setSerices(serices.toString()); - return chartsData; + return chartsDataList; } private static String stampToDate(String timeStamp) { @@ -426,24 +423,4 @@ public class JtlResolver { return after.format(before.parse(dateString)); } - private static int sortByDate(Map.Entry> map1, Map.Entry> map2) { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - Date date1 = null, date2 = null; - try { - date1 = simpleDateFormat.parse(map1.getKey()); - date2 = simpleDateFormat.parse(map2.getKey()); - } catch (ParseException e) { - e.printStackTrace(); - } - - Long time1 = date1.getTime(); - Long time2 = date2.getTime(); - - if (time1.equals(time2)) { - return 0; - } else { - return time1 > time2 ? 1 : -1; - } - - } } \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/report/base/ChartsData.java b/backend/src/main/java/io/metersphere/report/base/ChartsData.java index 3f4768adbc..617c45343c 100644 --- a/backend/src/main/java/io/metersphere/report/base/ChartsData.java +++ b/backend/src/main/java/io/metersphere/report/base/ChartsData.java @@ -1,23 +1,71 @@ package io.metersphere.report.base; +import java.math.BigDecimal; + public class ChartsData { + /** + * X 轴 + */ private String xAxis; - private String serices; + + /** + * Y 轴 + */ + private BigDecimal yAxis = BigDecimal.ZERO; + + /** + * Y 轴右侧 + */ + private BigDecimal yAxis2 = BigDecimal.ZERO; + + /** + * series 名称 + */ + private String groupName; + + /** + * 描述 + */ + private String description; public String getxAxis() { return xAxis; } public void setxAxis(String xAxis) { - this.xAxis=xAxis; + this.xAxis = xAxis; } - public String getSerices() { - return serices; + public BigDecimal getyAxis() { + return yAxis; } - public void setSerices(String serices) { - this.serices=serices; + public void setyAxis(BigDecimal yAxis) { + this.yAxis = yAxis; + } + + public BigDecimal getyAxis2() { + return yAxis2; + } + + public void setyAxis2(BigDecimal yAxis2) { + this.yAxis2 = yAxis2; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; } } diff --git a/backend/src/main/java/io/metersphere/service/ReportService.java b/backend/src/main/java/io/metersphere/service/ReportService.java index 1b968730c7..5ca591a00f 100644 --- a/backend/src/main/java/io/metersphere/service/ReportService.java +++ b/backend/src/main/java/io/metersphere/service/ReportService.java @@ -84,20 +84,20 @@ public class ReportService { return testOverview; } - public ChartsData getLoadChartData(String id) { + public List getLoadChartData(String id) { checkReportStatus(id); LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id); String content = loadTestReport.getContent(); - ChartsData chartsData = JtlResolver.getLoadChartData(content); - return chartsData; + List chartsDataList = JtlResolver.getLoadChartData(content); + return chartsDataList; } - public ChartsData getResponseTimeChartData(String id) { + public List getResponseTimeChartData(String id) { checkReportStatus(id); LoadTestReportWithBLOBs loadTestReport = loadTestReportMapper.selectByPrimaryKey(id); String content = loadTestReport.getContent(); - ChartsData chartsData = JtlResolver.getResponseTimeChartData(content); - return chartsData; + List chartsDataList = JtlResolver.getResponseTimeChartData(content); + return chartsDataList; } public void checkReportStatus(String reportId) { diff --git a/frontend/src/business/components/common/router/router.js b/frontend/src/business/components/common/router/router.js index 0dac4ad4af..7a70a42f38 100644 --- a/frontend/src/business/components/common/router/router.js +++ b/frontend/src/business/components/common/router/router.js @@ -214,7 +214,7 @@ const router = new VueRouter({ component: TestCase, }, { - path: "plan/:projectId", + path: "plan/:type", name: "testPlan", component: TestPlan }, diff --git a/frontend/src/business/components/performance/report/components/TestOverview.vue b/frontend/src/business/components/performance/report/components/TestOverview.vue index ef9e253eb3..a4547846c6 100644 --- a/frontend/src/business/components/performance/report/components/TestOverview.vue +++ b/frontend/src/business/components/performance/report/components/TestOverview.vue @@ -105,13 +105,8 @@ color: '#65A2FF' }, }, - legend: { - bottom: 10, - data: ['Users', 'Hits/s', 'Error(s)'] - }, - xAxis: { - type: 'category', - }, + legend: {}, + xAxis: {}, yAxis: [{ name: 'User', type: 'value', @@ -128,28 +123,9 @@ // interval: 5 / 5 } ], - series: [ - { - name: 'Users', - color: '#0CA74A', - type: 'line', - yAxisIndex: 0 - }, - { - name: 'Hits/s', - color: '#65A2FF', - type: 'line', - yAxisIndex: 1 - }, - { - name: 'Error(s)', - color: '#E6113C', - type: 'line', - yAxisIndex: 1 - } - ] + series: [] } - this.loadOption = this.generateLoadOption(loadOption, data); + this.loadOption = this.generateOption(loadOption, data); }) this.$get("/report/content/res_chart/" + this.id, res => { let data = res.data; @@ -162,13 +138,8 @@ color: '#99743C' }, }, - legend: { - bottom: 10, - data: ['Users', 'Response Time'] - }, - xAxis: { - type: 'category' - }, + legend: {}, + xAxis: {}, yAxis: [{ name: 'User', type: 'value', @@ -182,77 +153,40 @@ min: 0 } ], - series: [ - { - name: 'Users', - color: '#0CA74A', - type: 'line', - yAxisIndex: 0 - }, - { - name: 'Response Time', - color: '#99743C', - type: 'line', - yAxisIndex: 1 - } - ] + series: [] } - this.resOption = this.generateResponseOption(resOption, data); + this.resOption = this.generateOption(resOption, data); }) }, - _objToStrMap(obj){ - let strMap = new Map(); - for (let k of Object.keys(obj)) { - strMap.set(k,obj[k]); + generateOption(option, data) { + let chartData = data; + let legend = [], series = {}, xAxis = [], seriesData = []; + chartData.forEach(item => { + if (!xAxis.includes(item.xAxis)) { + xAxis.push(item.xAxis); + } + xAxis.sort() + let name = item.groupName + if (!legend.includes(name)) { + legend.push(name) + series[name] = [] + } + series[name].splice(xAxis.indexOf(item.xAxis), 0, item.yAxis.toFixed(2)); + }) + this.$set(option.legend, "data", legend); + this.$set(option.legend, "bottom", 10); + this.$set(option.xAxis, "data", xAxis); + for (let name in series) { + let data = series[name]; + let items = { + name: name, + type: 'line', + data: data + }; + seriesData.push(items); } - return strMap; - }, - _jsonToMap(jsonStr){ - return this._objToStrMap(JSON.parse(jsonStr)); - }, - generateLoadOption(loadOption, data) { - let map = this._jsonToMap(data.serices); - let xAxis = data.xAxis; - this.$set(loadOption.xAxis, "data", xAxis.split(',')); - let user = map.get("users").slice(0); - let hit = map.get("hits").slice(0); - user.sort(function (a,b) { - return parseInt(a) - parseInt(b); - }) - hit.sort(function (a,b) { - return parseFloat(a) - parseFloat(b); - }) - this.$set(loadOption.yAxis[0], "max",user[user.length-1]); - this.$set(loadOption.yAxis[0], "interval", user[user.length-1]/5); - this.$set(loadOption.yAxis[1], "max", hit[hit.length-1]); - this.$set(loadOption.yAxis[1], "interval", hit[hit.length-1]/5); - - this.$set(loadOption.series[0], "data", map.get("users")); - this.$set(loadOption.series[1], "data", map.get("hits")); - this.$set(loadOption.series[2], "data", map.get("errors")); - return loadOption; - }, - generateResponseOption(resOption, data) { - let map = this._jsonToMap(data.serices); - let user = map.get("users").slice(0); - let res = map.get("resTime").slice(0); - user.sort(function (a,b) { - return parseInt(a) - parseInt(b); - }) - res.sort(function (a,b) { - return parseFloat(a) - parseFloat(b); - }) - - this.$set(resOption.yAxis[0], "max",user[user.length-1]); - this.$set(resOption.yAxis[0], "interval", user[user.length-1]/5); - this.$set(resOption.yAxis[1], "max", res[res.length-1]); - this.$set(resOption.yAxis[1], "interval", res[res.length-1]/5); - - let xAxis = data.xAxis; - this.$set(resOption.xAxis, "data", xAxis.split(',')); - this.$set(resOption.series[0], "data", map.get("users")); - this.$set(resOption.series[1], "data", map.get("resTime")); - return resOption; + this.$set(option, "series", seriesData); + return option; }, }, watch: { diff --git a/frontend/src/business/components/track/case/TestCase.vue b/frontend/src/business/components/track/case/TestCase.vue index ca53e6415b..f92670db70 100644 --- a/frontend/src/business/components/track/case/TestCase.vue +++ b/frontend/src/business/components/track/case/TestCase.vue @@ -88,6 +88,7 @@ } if (path.indexOf("/track/case/edit") >= 0){ this.openRecentTestCaseEditDialog(); + this.$router.push('/track/case/all'); } } }, diff --git a/frontend/src/business/components/track/head/TrackHeaderMenus.vue b/frontend/src/business/components/track/head/TrackHeaderMenus.vue index 3dd23233a3..4bc6e8cfe4 100644 --- a/frontend/src/business/components/track/head/TrackHeaderMenus.vue +++ b/frontend/src/business/components/track/head/TrackHeaderMenus.vue @@ -31,9 +31,6 @@ {{$t('test_track.case_list')}} - - - = 0){ + this.openTestPlanEditDialog(); + this.$router.push('/track/plan/all'); + } + }, + watch: { + '$route'(to, from) { + if (to.path.indexOf("/track/plan/create") >= 0){ + this.openTestPlanEditDialog(); + this.$router.push('/track/plan/all'); + } + } + }, methods: { openTestPlanEditDialog(data) { this.$refs.testPlanEditDialog.openTestPlanEditDialog(data); diff --git a/frontend/src/business/components/track/plan/TestPlanView.vue b/frontend/src/business/components/track/plan/TestPlanView.vue index 180034012d..a1d5afe8c4 100644 --- a/frontend/src/business/components/track/plan/TestPlanView.vue +++ b/frontend/src/business/components/track/plan/TestPlanView.vue @@ -13,19 +13,20 @@ + @refresh="refresh"> @@ -65,7 +66,8 @@ }, methods: { refresh() { - + this.getPlanCases(); + this.getNodeTreeByPlanId(); }, getPlanCases(nodeIds) { this.$refs.testCasePlanList.initTableData(nodeIds); diff --git a/frontend/src/business/components/track/plan/components/TestCasePlanList.vue b/frontend/src/business/components/track/plan/components/TestCasePlanList.vue index f6795c47ad..66eb50b871 100644 --- a/frontend/src/business/components/track/plan/components/TestCasePlanList.vue +++ b/frontend/src/business/components/track/plan/components/TestCasePlanList.vue @@ -211,6 +211,7 @@ let testCaseId = testCase.id; this.$post('/test/plan/case/delete/' + testCaseId, {}, () => { this.initTableData(); + this.$emit("refresh"); this.$message({ message: this.$t('commons.delete_success'), type: 'success'