fix(测试跟踪): 修复测试计划报告导出时性能测试报告详情不显示的问题

--bug=1024105 --user=宋天阳 【测试跟踪】测试计划导出的报告-性能测试用例没有数据
https://www.tapd.cn/55049933/s/1350582
This commit is contained in:
song-tianyang 2023-03-15 15:49:38 +08:00 committed by 建国
parent a295a39ecb
commit 2c1fe4c70b
12 changed files with 1559 additions and 1090 deletions

View File

@ -531,7 +531,7 @@ public class TestPlanLoadCaseService {
}
public void buildLoadResponse(List<TestPlanLoadCaseDTO> cases) {
if (!org.apache.commons.collections.CollectionUtils.isEmpty(cases)) {
if (!CollectionUtils.isEmpty(cases)) {
cases.forEach(item -> {
LoadCaseReportRequest request = new LoadCaseReportRequest();
String reportId = item.getLoadReportId();

View File

@ -0,0 +1,16 @@
package io.metersphere.dto;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class LoadTestExportJmx {
private String name;
private String jmx;
public LoadTestExportJmx(String name, String jmx) {
this.name = name;
this.jmx = jmx;
}
}

View File

@ -2,14 +2,15 @@ package io.metersphere.dto;
import io.metersphere.base.domain.LoadTestReportWithBLOBs;
import io.metersphere.base.domain.TestPlanLoadCaseWithBLOBs;
import io.metersphere.plan.dto.ChartsData;
import io.metersphere.plan.dto.Errors;
import io.metersphere.plan.dto.ErrorsTop5;
import io.metersphere.plan.dto.Statistics;
import io.opentelemetry.sdk.metrics.data.MetricData;
import lombok.Getter;
import lombok.Setter;
import javax.management.monitor.Monitor;
import java.util.List;
import java.util.Map;
@ -34,8 +35,7 @@ public class TestPlanLoadCaseDTO extends TestPlanLoadCaseWithBLOBs {
private long startTime;
private long endTime;
private String fixLoadConfiguration;
// private LoadTestExportJmx jmxContent;
// private List<LoadTestExportJmx> fixJmxContent;
private List<LoadTestExportJmx> fixJmxContent;
private TestOverview testOverview;
private List<ChartsData> loadChartData;
private List<ChartsData> responseTimeChartData;
@ -46,8 +46,8 @@ public class TestPlanLoadCaseDTO extends TestPlanLoadCaseWithBLOBs {
private List<Errors> reportErrors;
private List<ErrorsTop5> reportErrorsTop5;
private List<LogDetailDTO> reportLogResource;
// private List<Monitor> reportResource;
// private List<MetricData> metricData;
private List<Monitor> reportResource;
private List<MetricData> metricData;
private List<TestResourcePoolDTO> resourcePools;
}
}

View File

@ -1,41 +1,101 @@
<template>
<div>
<el-row >
<el-col :span="12">
<ms-doughnut-pie-chart :name="$t('test_track.plan.test_plan_test_case_count')" :data="caseCharData" ref="functionChar"/>
</el-col>
<el-col :span="12">
<ms-doughnut-pie-chart :name="$t('test_track.plan_view.issues_count')" :data="issueCharData"/>
</el-col>
</el-row>
</div>
<div>
<el-row>
<el-col :span="12">
<ms-doughnut-pie-chart
:name="$t('test_track.plan.test_plan_test_case_count')"
:data="caseCharData"
ref="functionChar"
/>
</el-col>
<el-col :span="12">
<ms-doughnut-pie-chart
:name="$t('test_track.plan_view.issues_count')"
:data="issueCharData"
/>
</el-col>
</el-row>
</div>
</template>
<script>
import MsDoughnutPieChart from "metersphere-frontend/src/components/MsDoughnutPieChart";
export default {
name: "FunctionalResult",
components: {MsDoughnutPieChart},
components: { MsDoughnutPieChart },
data() {
return {
caseDataMap: new Map([
["Pass", {name: this.$t('test_track.plan_view.pass'), itemStyle: {color: '#67C23A'}}],
["Failure", {name: this.$t('test_track.plan_view.failure'), itemStyle: {color: '#F56C6C'}}],
["Blocking", {name: this.$t('test_track.plan_view.blocking'), itemStyle: {color: '#E6A23C'}}],
["Skip", {name: this.$t('test_track.plan_view.skip'), itemStyle: {color: '#909399'}}],
["Underway", {name: this.$t('test_track.plan.plan_status_running'), itemStyle: {color: 'lightskyblue'}}],
["Prepare", {name: this.$t('test_track.plan.plan_status_prepare'), itemStyle: {color: '#DEDE10'}}]
[
"Pass",
{
name: this.$t("test_track.plan_view.pass"),
itemStyle: { color: "#67C23A" },
},
],
[
"Failure",
{
name: this.$t("test_track.plan_view.failure"),
itemStyle: { color: "#F56C6C" },
},
],
[
"Blocking",
{
name: this.$t("test_track.plan_view.blocking"),
itemStyle: { color: "#E6A23C" },
},
],
[
"Skip",
{
name: this.$t("test_track.plan_view.skip"),
itemStyle: { color: "#909399" },
},
],
[
"Underway",
{
name: this.$t("test_track.plan.plan_status_running"),
itemStyle: { color: "lightskyblue" },
},
],
[
"Prepare",
{
name: this.$t("test_track.plan.plan_status_prepare"),
itemStyle: { color: "#DEDE10" },
},
],
]),
issueDataMap: new Map([
["resolved", {name: this.$t('test_track.issue.status_resolved'), itemStyle: {color: '#67C23A'}}],
["new", {name: this.$t('test_track.issue.status_new'), itemStyle: {color: '#F56C6C'}}],
["closed", {name: this.$t('test_track.issue.status_closed'), itemStyle: {color: '#909399'}}],
[
"resolved",
{
name: this.$t("test_track.issue.status_resolved"),
itemStyle: { color: "#67C23A" },
},
],
[
"new",
{
name: this.$t("test_track.issue.status_new"),
itemStyle: { color: "#F56C6C" },
},
],
[
"closed",
{
name: this.$t("test_track.issue.status_closed"),
itemStyle: { color: "#909399" },
},
],
]),
caseCharData: [],
issueCharData: [],
isShow: true
}
isShow: true,
};
},
props: {
functionResult: {
@ -43,15 +103,15 @@ export default {
default() {
return {
caseData: [],
issueData: []
}
}
}
issueData: [],
};
},
},
},
watch: {
functionResult() {
this.getCaseCharData();
}
},
},
created() {
this.getCaseCharData();
@ -59,7 +119,7 @@ export default {
methods: {
getCaseCharData() {
let caseCharData = [];
this.functionResult.caseData.forEach(item => {
this.functionResult.caseData.forEach((item) => {
let data = this.caseDataMap.get(item.status);
data.value = item.count;
caseCharData.push(data);
@ -67,46 +127,51 @@ export default {
this.caseCharData = caseCharData;
let issueCharData = [];
let colors = ['#67C23A', '#E6A23C','#DEDE10',
'#F56C6C','#909399'];
let colors = ["#67C23A", "#E6A23C", "#DEDE10", "#F56C6C", "#909399"];
let usedSet = new Set();
this.functionResult.issueData.forEach(item => {
let status = item.status;
let data = this.issueDataMap.get(status);
if (!data) {
data = {name: status, itemStyle: {color: null}};
if (status === 'new' || status === '新' || status === '待办' || status === 'active' || status === 'created') {
data.itemStyle.color = '#F56C6C';
usedSet.add(data.itemStyle.color);
}
if (status === '已拒绝' || status === 'reject') {
data.itemStyle.color = '#909399';
usedSet.add(data.itemStyle.color);
}
if (status === '已关闭' || status === 'close') {
data.itemStyle.color = '#67C23A';
usedSet.add(data.itemStyle.color);
}
if (!data.itemStyle.color) {
for (let i = 0; i < colors.length; i++) {
let color = colors[i];
if (!usedSet.has(color)) {
data.itemStyle.color = color;
usedSet.add(data.itemStyle.color);
break;
if (this.functionResult.issueData) {
this.functionResult.issueData.forEach((item) => {
let status = item.status;
let data = this.issueDataMap.get(status);
if (!data) {
data = { name: status, itemStyle: { color: null } };
if (
status === "new" ||
status === "新" ||
status === "待办" ||
status === "active" ||
status === "created"
) {
data.itemStyle.color = "#F56C6C";
usedSet.add(data.itemStyle.color);
}
if (status === "已拒绝" || status === "reject") {
data.itemStyle.color = "#909399";
usedSet.add(data.itemStyle.color);
}
if (status === "已关闭" || status === "close") {
data.itemStyle.color = "#67C23A";
usedSet.add(data.itemStyle.color);
}
if (!data.itemStyle.color) {
for (let i = 0; i < colors.length; i++) {
let color = colors[i];
if (!usedSet.has(color)) {
data.itemStyle.color = color;
usedSet.add(data.itemStyle.color);
break;
}
}
}
}
}
data.value = item.count;
issueCharData.push(data);
});
data.value = item.count;
issueCharData.push(data);
});
}
this.issueCharData = issueCharData;
},
}
}
},
};
</script>
<style scoped>
</style>
<style scoped></style>

View File

@ -6,30 +6,30 @@
border
stripe
style="width: 100%"
:default-sort="{prop: 'elementLabel'}"
:default-sort="{ prop: 'elementLabel' }"
>
<el-table-column
prop="errorType"
label="Type of error"
sortable>
<el-table-column prop="errorType" label="Type of error" sortable>
</el-table-column>
<el-table-column
width="200"
prop="errorNumber"
label="Number of errors"
sortable>
sortable
>
</el-table-column>
<el-table-column
width="200"
prop="percentOfErrors"
label="% in errors"
sortable>
sortable
>
</el-table-column>
<el-table-column
width="200"
prop="percentOfAllSamples"
label="% in all samples"
sortable>
sortable
>
</el-table-column>
</el-table>
@ -41,75 +41,49 @@
style="width: 100%"
show-summary
>
<el-table-column prop="sample" label="Sample"/>
<el-table-column prop="samples" label="#Samples"/>
<el-table-column prop="errorsAllSize" label="All Errors"/>
<el-table-column prop="sample" label="Sample" />
<el-table-column prop="samples" label="#Samples" />
<el-table-column prop="errorsAllSize" label="All Errors" />
</el-table>
<span class="table-title">#1 Error</span>
<el-table
:data="errorTop1"
border
stripe
style="width: 100%"
>
<el-table-column prop="sample" label="Sample"/>
<el-table-column prop="error1" label="#1 Error"/>
<el-table-column prop="error1Size" label="#1 Errors Count" width="200"/>
<el-table :data="errorTop1" border stripe style="width: 100%">
<el-table-column prop="sample" label="Sample" />
<el-table-column prop="error1" label="#1 Error" />
<el-table-column prop="error1Size" label="#1 Errors Count" width="200" />
</el-table>
<span class="table-title">#2 Error</span>
<el-table
:data="errorTop2"
border
stripe
style="width: 100%"
>
<el-table-column prop="sample" label="Sample"/>
<el-table-column prop="error2" label="#2 Error"/>
<el-table-column prop="error2Size" label="#2 Errors Count" width="200"/>
<el-table :data="errorTop2" border stripe style="width: 100%">
<el-table-column prop="sample" label="Sample" />
<el-table-column prop="error2" label="#2 Error" />
<el-table-column prop="error2Size" label="#2 Errors Count" width="200" />
</el-table>
<span class="table-title">#3 Error</span>
<el-table
:data="errorTop3"
border
stripe
style="width: 100%"
>
<el-table-column prop="sample" label="Sample"/>
<el-table-column prop="error3" label="#3 Error"/>
<el-table-column prop="error3Size" label="#3 Errors Count" width="200"/>
<el-table :data="errorTop3" border stripe style="width: 100%">
<el-table-column prop="sample" label="Sample" />
<el-table-column prop="error3" label="#3 Error" />
<el-table-column prop="error3Size" label="#3 Errors Count" width="200" />
</el-table>
<span class="table-title">#4 Error</span>
<el-table
:data="errorTop4"
border
stripe
style="width: 100%"
>
<el-table-column prop="sample" label="Sample"/>
<el-table-column prop="error4" label="#4 Error"/>
<el-table-column prop="error4Size" label="#4 Errors Count" width="200"/>
<el-table :data="errorTop4" border stripe style="width: 100%">
<el-table-column prop="sample" label="Sample" />
<el-table-column prop="error4" label="#4 Error" />
<el-table-column prop="error4Size" label="#4 Errors Count" width="200" />
</el-table>
<span class="table-title">#5 Error</span>
<el-table
:data="errorTop5"
border
stripe
style="width: 100%"
>
<el-table-column prop="sample" label="Sample"/>
<el-table-column prop="error5" label="#5 Error"/>
<el-table-column prop="error5Size" label="#5 Errors Count" width="200"/>
<el-table :data="errorTop5" border stripe style="width: 100%">
<el-table-column prop="sample" label="Sample" />
<el-table-column prop="error5" label="#5 Error" />
<el-table-column prop="error5Size" label="#5 Errors Count" width="200" />
</el-table>
</div>
</template>
<script>
export default {
name: "ErrorLog",
data() {
@ -121,10 +95,13 @@ export default {
errorTop3: [],
errorTop4: [],
errorTop5: [],
id: ''
id: "",
};
},
props: ['report', 'isShare', 'shareId', 'planReportTemplate'],
props: ["report", "isShare", "shareId", "planReportTemplate"],
created() {
this.initTableData();
},
methods: {
initTableData() {
if (this.planReportTemplate) {
@ -137,37 +114,61 @@ export default {
return;
}
this.errorTop1 = data
.map(e => {
return {sample: e.sample, error1: e.error1, error1Size: e.error1Size};
.map((e) => {
return {
sample: e.sample,
error1: e.error1,
error1Size: e.error1Size,
};
})
.filter(e => e.error1Size > 0);
.filter((e) => e.error1Size > 0);
this.errorTop2 = data
.map(e => {
return {sample: e.sample, error2: e.error2, error2Size: e.error2Size};
.map((e) => {
return {
sample: e.sample,
error2: e.error2,
error2Size: e.error2Size,
};
})
.filter(e => e.error2Size > 0);
.filter((e) => e.error2Size > 0);
this.errorTop3 = data
.map(e => {
return {sample: e.sample, error3: e.error3, error3Size: e.error3Size};
.map((e) => {
return {
sample: e.sample,
error3: e.error3,
error3Size: e.error3Size,
};
})
.filter(e => e.error3Size > 0);
.filter((e) => e.error3Size > 0);
this.errorTop4 = data
.map(e => {
return {sample: e.sample, error4: e.error4, error4Size: e.error4Size};
.map((e) => {
return {
sample: e.sample,
error4: e.error4,
error4Size: e.error4Size,
};
})
.filter(e => e.error4Size > 0);
.filter((e) => e.error4Size > 0);
this.errorTop5 = data
.map(e => {
return {sample: e.sample, error5: e.error5, error5Size: e.error5Size};
.map((e) => {
return {
sample: e.sample,
error5: e.error5,
error5Size: e.error5Size,
};
})
.filter(e => e.error5Size > 0);
.filter((e) => e.error5Size > 0);
this.errorSummary = data.map(e => {
return {sample: e.sample, samples: e.samples, errorsAllSize: e.errorsAllSize};
this.errorSummary = data.map((e) => {
return {
sample: e.sample,
samples: e.samples,
errorsAllSize: e.errorsAllSize,
};
});
},
initData() {
@ -178,7 +179,7 @@ export default {
this.errorTop4 = [];
this.errorTop5 = [];
this.errorSummary = [];
}
},
},
watch: {
report: {
@ -200,7 +201,7 @@ export default {
this.errorSummary = [];
}
},
deep: true
deep: true,
},
planReportTemplate: {
handler() {
@ -208,8 +209,8 @@ export default {
this.initTableData();
}
},
deep: true
}
deep: true,
},
},
};
</script>

View File

@ -2,21 +2,30 @@
<div>
<el-row :gutter="10">
<el-col :span="4">
<el-select v-model="currentInstance" placeholder="" size="small" style="width: 100%"
@change="changeInstance(currentInstance)">
<el-select
v-model="currentInstance"
placeholder=""
size="small"
style="width: 100%"
@change="changeInstance(currentInstance)"
>
<el-option
v-for="item in resource"
:key="item.resourceId"
:label="item.resourceName"
:value="item.resourceId">
:value="item.resourceId"
>
</el-option>
</el-select>
</el-col>
<el-col :span="20">
<div class="logging-content" v-loading="loading">
<ul class="infinite-list">
<li class="infinite-list-item" v-for="(log, index) in logContent"
:key="currentInstance+index">
<li
class="infinite-list-item"
v-for="(log, index) in logContent"
:key="currentInstance + index"
>
{{ log.content }}
</li>
</ul>
@ -27,7 +36,6 @@
</template>
<script>
export default {
name: "LogDetails",
data() {
@ -35,14 +43,17 @@ export default {
resource: [],
logContent: [],
result: {},
id: '',
id: "",
page: 1,
pageCount: 5,
loading: false,
currentInstance: ''
currentInstance: "",
};
},
props: ['report', 'export', 'isShare', 'shareId', 'planReportTemplate'],
props: ["report", "export", "isShare", "shareId", "planReportTemplate"],
created() {
this.getResource();
},
methods: {
getResource() {
if (this.planReportTemplate) {
@ -66,9 +77,9 @@ export default {
}
this.loading = true;
if (this.planReportTemplate) {
let {reportLogResource} = this.planReportTemplate;
let { reportLogResource } = this.planReportTemplate;
if (reportLogResource && reportLogResource.length > 0) {
let {reportLogs} = reportLogResource[0];
let { reportLogs } = reportLogResource[0];
if (reportLogs) {
this.handleGetPlanTemplateLog(reportLogs);
}
@ -76,7 +87,7 @@ export default {
}
},
handleGetPlanTemplateLog(data) {
data.forEach(log => {
data.forEach((log) => {
if (this.logContent) {
this.logContent.push(log);
}
@ -92,9 +103,9 @@ export default {
},
},
watch: {
'$route'(to) {
$route(to) {
if (to.name === "perReportView") {
this.id = to.path.split('/')[4];
this.id = to.path.split("/")[4];
this.getResource();
}
},
@ -109,7 +120,7 @@ export default {
this.getResource();
}
},
deep: true
deep: true,
},
planReportTemplate: {
handler() {
@ -117,8 +128,8 @@ export default {
this.getResource();
}
},
deep: true
}
deep: true,
},
},
};
</script>
@ -134,11 +145,10 @@ export default {
padding: 0;
margin: 0;
list-style: none;
overflow: auto
overflow: auto;
}
.infinite-list-item {
overflow: hidden;
}
</style>

View File

@ -3,24 +3,30 @@
<el-row>
<el-col :span="4">
<div>
<el-select v-model="currentInstance" placeholder="" size="small" style="width: 100%"
@change="getResource(currentInstance)">
<el-select
v-model="currentInstance"
placeholder=""
size="small"
style="width: 100%"
@change="getResource(currentInstance)"
>
<el-option
v-for="item in instances"
:key="item.ip+item.port"
:value="item.ip+':'+item.port">
:key="item.ip + item.port"
:value="item.ip + ':' + item.port"
>
{{ item.ip }} {{ item.name }}
</el-option>
</el-select>
</div>
<div style="padding-top: 10px">
<el-checkbox-group v-model="checkList"
@change="handleCheckListChange(currentInstance)">
<div v-for="op in checkOptions"
:key="op.key"
:content="op.label">
<el-checkbox :label="op.label"/>
<el-checkbox-group
v-model="checkList"
@change="handleCheckListChange(currentInstance)"
>
<div v-for="op in checkOptions" :key="op.key" :content="op.label">
<el-checkbox :label="op.label" />
</div>
</el-checkbox-group>
</div>
@ -28,56 +34,31 @@
<el-col :span="20">
<el-row>
<el-col :span="24">
<ms-chart v-if="showChart" ref="chart2" class="chart-config" @datazoom="changeDataZoom"
:options="totalOption"
:autoresize="true"></ms-chart>
<ms-chart
v-if="showChart"
ref="chart2"
class="chart-config"
@datazoom="changeDataZoom"
:options="totalOption"
:autoresize="true"
></ms-chart>
</el-col>
</el-row>
<el-row>
<el-col :offset="2" :span="20">
<el-table
:data="tableData"
stripe
border
style="width: 100%">
<el-table :data="tableData" stripe border style="width: 100%">
<el-table-column label="Label" align="center">
<el-table-column
prop="label"
label="Label"
sortable>
<el-table-column prop="label" label="Label" sortable>
</el-table-column>
</el-table-column>
<el-table-column label="Aggregate" align="center">
<el-table-column
prop="avg"
label="Avg."
width="100"
sortable
/>
<el-table-column
prop="min"
label="Min."
width="100"
sortable
/>
<el-table-column
prop="max"
label="Max."
width="100"
sortable
/>
<el-table-column prop="avg" label="Avg." width="100" sortable />
<el-table-column prop="min" label="Min." width="100" sortable />
<el-table-column prop="max" label="Max." width="100" sortable />
</el-table-column>
<el-table-column label="Range" align="center">
<el-table-column
prop="startTime"
label="Start"
width="160"
/>
<el-table-column
prop="endTime"
label="End"
width="160"
/>
<el-table-column prop="startTime" label="Start" width="160" />
<el-table-column prop="endTime" label="End" width="160" />
</el-table-column>
</el-table>
</el-col>
@ -88,31 +69,42 @@
</template>
<script>
import MsChart from "metersphere-frontend/src/components/chart/MsChart";
const color = ['#60acfc', '#32d3eb', '#5bc49f', '#feb64d', '#ff7c7c', '#9287e7', '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'];
const checkList = ['CPU', 'Memory', 'Disk', 'Network In', 'Network Out'];
const color = [
"#60acfc",
"#32d3eb",
"#5bc49f",
"#feb64d",
"#ff7c7c",
"#9287e7",
"#ca8622",
"#bda29a",
"#6e7074",
"#546570",
"#c4ccd3",
];
const checkList = ["CPU", "Memory", "Disk", "Network In", "Network Out"];
const checkOptions = [
{key: 'cpu', label: 'CPU'},
{key: 'memory', label: 'Memory'},
{key: 'disk', label: 'Disk'},
{key: 'netIn', label: 'Network In'},
{key: 'netOut', label: 'Network Out'}
{ key: "cpu", label: "CPU" },
{ key: "memory", label: "Memory" },
{ key: "disk", label: "Disk" },
{ key: "netIn", label: "Network In" },
{ key: "netOut", label: "Network Out" },
];
export default {
name: "MonitorCard",
props: ['report', 'export', 'isShare', 'shareId', 'planReportTemplate'],
components: {MsChart},
props: ["report", "export", "isShare", "shareId", "planReportTemplate"],
components: { MsChart },
data() {
return {
activeNames: '0',
activeNames: "0",
result: {},
id: '',
id: "",
init: false,
loading: false,
currentInstance: '',
currentInstance: "",
instances: [],
data: [],
tableData: [],
@ -126,37 +118,40 @@ export default {
},
title: {},
tooltip: {
trigger: 'axis',
trigger: "axis",
axisPointer: {
type: 'cross'
type: "cross",
},
},
legend: {
y: 'top'
y: "top",
},
xAxis: {type: 'category'},
yAxis: [{
name: 'Usage(%)',
type: 'value',
min: 0,
max: 100,
}, {
type: 'value',
name: 'kb/s',
min: 0,
}],
xAxis: { type: "category" },
yAxis: [
{
name: "Usage(%)",
type: "value",
min: 0,
max: 100,
},
{
type: "value",
name: "kb/s",
min: 0,
},
],
dataZoom: [
{
type: 'inside',
type: "inside",
start: 0,
end: 100
end: 100,
},
{
start: 0,
end: 20
}
end: 20,
},
],
series: []
series: [],
},
totalOption: {},
seriesData: [],
@ -165,25 +160,35 @@ export default {
created() {
this.data = [];
this.instances = [];
this.getResource();
},
methods: {
getResource(currentInstance) {
// this.init = true;
if (this.planReportTemplate) {
this.instances = this.planReportTemplate.reportResource;
this.currentInstance = currentInstance || this.instances[0]?.ip + ":" + this.instances[0]?.port;
this.data = this.planReportTemplate.metricData;
this.totalOption = this.getOption(this.currentInstance);
if (this.instances) {
this.currentInstance =
currentInstance ||
this.instances[0]?.ip + ":" + this.instances[0]?.port;
}
if (this.planReportTemplate.metricData) {
this.data = this.planReportTemplate.metricData;
this.totalOption = this.getOption(this.currentInstance);
}
}
},
handleChecked(id) {
let curr = this.instances.filter(instance => id === instance.ip + ":" + instance.port)[0];
let curr = this.instances.filter(
(instance) => id === instance.ip + ":" + instance.port
)[0];
if (curr && curr.monitorConfig) {
this.checkList = [];
this.checkOptions = curr.monitorConfig.filter(mc => mc.value && mc.name)
.map(mc => {
this.checkOptions = curr.monitorConfig
.filter((mc) => mc.value && mc.name)
.map((mc) => {
this.checkList.push(mc.name);
return {key: mc.name, label: mc.name,};
return { key: mc.name, label: mc.name };
});
if (this.checkList.length === 0) {
this.checkList = checkList;
@ -196,7 +201,7 @@ export default {
this.totalOption = {};
this.$nextTick(() => {
this.totalOption = this.getOption(id);
this.changeDataZoom({start: 0, end: 100});
this.changeDataZoom({ start: 0, end: 100 });
});
},
handleCheckListChange(id) {
@ -205,7 +210,7 @@ export default {
this.$nextTick(() => {
this.showChart = true;
this.totalOption = this.getOption(id);
this.changeDataZoom({start: 0, end: 100});
this.changeDataZoom({ start: 0, end: 100 });
});
},
getOption(id) {
@ -213,12 +218,12 @@ export default {
let series = [];
for (const name of this.checkList) {
let check = this.checkOptions.filter(op => op.label === name)[0].key;
let check = this.checkOptions.filter((op) => op.label === name)[0].key;
let yAxisIndex = 1;
if (check === 'cpu' || check === 'memory' || check === 'disk') {
if (check === "cpu" || check === "memory" || check === "disk") {
yAxisIndex = 0;
}
this.data.forEach(d => {
this.data.forEach((d) => {
if (d.instance === id && d.seriesName === check) {
if (legend.indexOf(name) > -1) {
return;
@ -226,7 +231,7 @@ export default {
this.baseOption.xAxis.data = d.timestamps;
let yAxis = d.values.map(v => v.toFixed(2));
let yAxis = d.values.map((v) => v.toFixed(2));
let data = [];
for (let i = 0; i < d.timestamps.length; i++) {
data.push([d.timestamps[i], yAxis[i]]);
@ -236,10 +241,10 @@ export default {
series.push({
name: name,
data: data,
type: 'line',
type: "line",
yAxisIndex: yAxisIndex,
smooth: true,
sampling: 'lttb',
sampling: "lttb",
showSymbol: false,
});
@ -261,9 +266,15 @@ export default {
let tableData = [];
for (let i = 0; i < this.seriesData.length; i++) {
let sub = this.seriesData[i].data, label = this.seriesData[i].name;
let sub = this.seriesData[i].data,
label = this.seriesData[i].name;
let len = 0;
let min, avg, max, sum = 0, startTime, endTime;
let min,
avg,
max,
sum = 0,
startTime,
endTime;
for (let j = 0; j < sub.length; j++) {
let time = sub[j][0];
let value = Number.parseFloat(sub[j][1]);
@ -296,7 +307,7 @@ export default {
}
avg = (sum / len).toFixed(2);
tableData.push({label, min, max, avg, startTime, endTime});
tableData.push({ label, min, max, avg, startTime, endTime });
}
this.tableData = tableData;
},
@ -318,7 +329,7 @@ export default {
this.instances = [];
}
},
deep: true
deep: true,
},
planReportTemplate: {
handler() {
@ -326,8 +337,8 @@ export default {
this.getResource();
}
},
deep: true
}
deep: true,
},
},
};
</script>
@ -342,7 +353,7 @@ export default {
overflow: auto;
}
:deep(.el-checkbox__label ) {
:deep(.el-checkbox__label) {
font-size: 10px !important;
}
</style>

View File

@ -8,35 +8,31 @@
style="width: 100%"
>
<el-table-column label="Requests" min-width="150" align="center">
<el-table-column
prop="label"
label="Label"
sortable
min-width="150">
<template v-slot:header="{column}">
<el-table-column prop="label" label="Label" sortable min-width="150">
<template v-slot:header="{ column }">
<span>Label</span>
<i class="el-icon-search" style="margin-left: 8px;cursor: pointer;font-weight: bold;"
@click="click(column)"></i>
<el-input v-model="searchLabel"
placeholder="请输入 Label 搜索"
size="mini"
class="search_input"
style="width: 100px; margin-left: 5px"
v-if="column.showSearch"
clearable
@clear="filterLabel"
@keyup.enter.native="filterLabel"/>
<i
class="el-icon-search"
style="margin-left: 8px; cursor: pointer; font-weight: bold"
@click="click(column)"
></i>
<el-input
v-model="searchLabel"
placeholder="请输入 Label 搜索"
size="mini"
class="search_input"
style="width: 100px; margin-left: 5px"
v-if="column.showSearch"
clearable
@clear="filterLabel"
@keyup.enter.native="filterLabel"
/>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="Executions" align="center">
<el-table-column
prop="samples"
label="Samples"
sortable
width="110"
/>
<el-table-column prop="samples" label="Samples" sortable width="110" />
<el-table-column
prop="fail"
@ -46,57 +42,17 @@
min-width="60"
/>
<el-table-column
prop="error"
label="Error%"
sortable
align="center"
/>
<el-table-column prop="error" label="Error%" sortable align="center" />
</el-table-column>
<el-table-column label="Response Times(ms)" align="center">
<el-table-column
prop="average"
label="Avg"
sortable
min-width="60"
/>
<el-table-column
prop="min"
label="Min"
sortable
min-width="60"
/>
<el-table-column
prop="max"
label="Max"
sortable
min-width="60"
/>
<el-table-column
prop="median"
label="Med"
sortable
min-width="60"
/>
<el-table-column
prop="tp90"
label="90%"
sortable
min-width="60"
/>
<el-table-column
prop="tp95"
label="95%"
sortable
min-width="60"
/>
<el-table-column
prop="tp99"
label="99%"
sortable
min-width="60"
/>
<el-table-column prop="average" label="Avg" sortable min-width="60" />
<el-table-column prop="min" label="Min" sortable min-width="60" />
<el-table-column prop="max" label="Max" sortable min-width="60" />
<el-table-column prop="median" label="Med" sortable min-width="60" />
<el-table-column prop="tp90" label="90%" sortable min-width="60" />
<el-table-column prop="tp95" label="95%" sortable min-width="60" />
<el-table-column prop="tp99" label="99%" sortable min-width="60" />
</el-table-column>
<el-table-column label="Throughput">
@ -124,7 +80,6 @@
width="100"
/>
</el-table-column>
</el-table>
</div>
</template>
@ -136,13 +91,16 @@ export default {
return {
tableData: [],
originalData: [],
id: '',
searchLabel: '',
id: "",
searchLabel: "",
showSearch: false,
showBtn: true,
}
};
},
props: ["report", "isShare", "shareId", "planReportTemplate"],
created() {
this.initTableData();
},
props: ['report', 'isShare', 'shareId', 'planReportTemplate'],
methods: {
initTableData() {
if (this.planReportTemplate) {
@ -152,16 +110,20 @@ export default {
}
},
click(column) {
this.searchLabel = '';
this.searchLabel = "";
this.tableData = this.originalData;
this.$set(column, 'showSearch', !column.showSearch);
this.$set(column, "showSearch", !column.showSearch);
},
filterLabel() {
this.tableData = this.searchLabel ? this.originalData.filter(this.createFilter(this.searchLabel)) : this.originalData;
this.tableData = this.searchLabel
? this.originalData.filter(this.createFilter(this.searchLabel))
: this.originalData;
},
createFilter(queryString) {
return item => {
return (item.label.toLowerCase().indexOf(queryString.toLowerCase()) !== -1);
return (item) => {
return (
item.label.toLowerCase().indexOf(queryString.toLowerCase()) !== -1
);
};
},
},
@ -179,7 +141,7 @@ export default {
this.tableData = [];
}
},
deep: true
deep: true,
},
planReportTemplate: {
handler() {
@ -187,14 +149,14 @@ export default {
this.initTableData();
}
},
deep: true
}
}
}
deep: true,
},
},
};
</script>
<style scoped>
.search_input :deep( .el-input__inner ) {
.search_input :deep(.el-input__inner) {
border-radius: 50px;
}
</style>

View File

@ -1,12 +1,25 @@
<template>
<el-tabs v-model="active">
<el-tab-pane :label="$t('load_test.pressure_config')">
<performance-pressure-config :is-read-only="true" :test="test" :report="report" :report-id="reportId"
:is-share="isShare" :share-id="shareId" @fileChange="fileChange"/>
<performance-pressure-config
:is-read-only="true"
:test="test"
:report="defaultReport"
:report-id="reportId"
:is-share="isShare"
:share-id="shareId"
@fileChange="fileChange"
/>
</el-tab-pane>
<el-tab-pane :label="$t('load_test.advanced_config')">
<performance-advanced-config :is-read-only="true" :report-id="reportId" :report="report" :is-share="isShare"
:share-id="shareId" ref="advancedConfig"/>
<performance-advanced-config
:is-read-only="true"
:report-id="reportId"
:report="defaultReport"
:is-share="isShare"
:share-id="shareId"
ref="advancedConfig"
/>
</el-tab-pane>
</el-tabs>
</template>
@ -17,11 +30,12 @@ import PerformanceAdvancedConfig from "../../../load/PerformanceAdvancedConfig";
export default {
name: "TestConfiguration",
components: {PerformancePressureConfig, PerformanceAdvancedConfig},
components: { PerformancePressureConfig, PerformanceAdvancedConfig },
data() {
return {
active: '0'
}
active: "0",
defaultReport: {},
};
},
props: {
test: Object,
@ -30,26 +44,33 @@ export default {
report: Object,
isShare: Boolean,
shareId: String,
planReportTemplate: Object,
},
created() {
if (this.planReportTemplate) {
this.defaultReport = this.planReportTemplate;
} else {
this.defaultReport = this.report;
}
},
methods: {
fileChange(threadGroups) {
let csvSet = new Set;
threadGroups.forEach(tg => {
let csvSet = new Set();
threadGroups.forEach((tg) => {
if (tg.csvFiles) {
tg.csvFiles.map(item => csvSet.add(item));
tg.csvFiles.map((item) => csvSet.add(item));
}
});
let csvFiles = [];
for (const f of csvSet) {
csvFiles.push({name: f, csvSplit: false, csvHasHeader: true});
csvFiles.push({ name: f, csvSplit: false, csvHasHeader: true });
}
if (this.$refs.advancedConfig) {
this.$refs.advancedConfig.csvFiles = csvFiles;
}
this.$refs.advancedConfig.csvFiles = csvFiles;
},
}
},
};
</script>
<style scoped>
</style>
<style scoped></style>

View File

@ -2,33 +2,49 @@
<div>
<el-row>
<el-col :span="6">
<div style="padding-bottom: 5px;">
<el-link type="primary" @click="resetDefault()">{{ $t('load_test.report.set_default') }}</el-link>
<div style="padding-bottom: 5px">
<el-link type="primary" @click="resetDefault()">{{
$t("load_test.report.set_default")
}}</el-link>
</div>
<el-collapse v-model="activeNames" class="test-detail">
<el-collapse-item name="users">
<template v-slot:title>
<div style="width: 100%">
<span>{{ $t('load_test.report.ActiveThreadsChart') }}</span>
<span style="float:right;">
<el-link type="primary" @click="selectAll( 'ActiveThreadsChart', $event)">
{{ $t('load_test.report.select_all') }}
<span>{{ $t("load_test.report.ActiveThreadsChart") }}</span>
<span style="float: right">
<el-link
type="primary"
@click="selectAll('ActiveThreadsChart', $event)"
>
{{ $t("load_test.report.select_all") }}
</el-link>
/
<el-link type="default" @click="unselectAll('ActiveThreadsChart', $event)">
{{ $t('load_test.report.unselect_all') }}
<el-link
type="default"
@click="unselectAll('ActiveThreadsChart', $event)"
>
{{ $t("load_test.report.unselect_all") }}
</el-link>
</span>
</div>
</template>
<el-checkbox-group v-model="checkList['ActiveThreadsChart']"
@change="handleChecked('ActiveThreadsChart')">
<div v-for="name in checkOptions['ActiveThreadsChart']" :key="name">
<el-tooltip class="item" effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top">
<el-checkbox :label="name"/>
<el-checkbox-group
v-model="checkList['ActiveThreadsChart']"
@change="handleChecked('ActiveThreadsChart')"
>
<div
v-for="name in checkOptions['ActiveThreadsChart']"
:key="name"
>
<el-tooltip
class="item"
effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top"
>
<el-checkbox :label="name" />
</el-tooltip>
</div>
</el-checkbox-group>
@ -36,27 +52,40 @@
<el-collapse-item name="transactions">
<template v-slot:title>
<div style="width: 100%">
<span>{{ $t('load_test.report.TransactionsChart') }}</span>
<span style="float:right;">
<el-link type="primary" @click="selectAll( 'TransactionsChart', $event)">
{{ $t('load_test.report.select_all') }}
<span>{{ $t("load_test.report.TransactionsChart") }}</span>
<span style="float: right">
<el-link
type="primary"
@click="selectAll('TransactionsChart', $event)"
>
{{ $t("load_test.report.select_all") }}
</el-link>
/
<el-link type="default" @click="unselectAll('TransactionsChart', $event)">
{{ $t('load_test.report.unselect_all') }}
<el-link
type="default"
@click="unselectAll('TransactionsChart', $event)"
>
{{ $t("load_test.report.unselect_all") }}
</el-link>
</span>
</div>
</template>
<el-checkbox-group v-model="checkList['TransactionsChart']" @change="handleChecked('TransactionsChart')">
<div v-for="name in checkOptions['TransactionsChart']"
:key="name">
<el-tooltip class="item" effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top">
<el-checkbox :label="name"/>
<el-checkbox-group
v-model="checkList['TransactionsChart']"
@change="handleChecked('TransactionsChart')"
>
<div
v-for="name in checkOptions['TransactionsChart']"
:key="name"
>
<el-tooltip
class="item"
effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top"
>
<el-checkbox :label="name" />
</el-tooltip>
</div>
</el-checkbox-group>
@ -64,26 +93,40 @@
<el-collapse-item name="responseTime">
<template v-slot:title>
<div style="width: 100%">
<span>{{ $t('load_test.report.ResponseTimeChart') }}</span>
<span style="float:right;">
<el-link type="primary" @click="selectAll( 'ResponseTimeChart', $event)">
{{ $t('load_test.report.select_all') }}
<span>{{ $t("load_test.report.ResponseTimeChart") }}</span>
<span style="float: right">
<el-link
type="primary"
@click="selectAll('ResponseTimeChart', $event)"
>
{{ $t("load_test.report.select_all") }}
</el-link>
/
<el-link type="default" @click="unselectAll('ResponseTimeChart', $event)">
{{ $t('load_test.report.unselect_all') }}
<el-link
type="default"
@click="unselectAll('ResponseTimeChart', $event)"
>
{{ $t("load_test.report.unselect_all") }}
</el-link>
</span>
</div>
</template>
<el-checkbox-group v-model="checkList['ResponseTimeChart']" @change="handleChecked('ResponseTimeChart')">
<div v-for="name in checkOptions['ResponseTimeChart']"
:key="name">
<el-tooltip class="item" effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top">
<el-checkbox :label="name"/>
<el-checkbox-group
v-model="checkList['ResponseTimeChart']"
@change="handleChecked('ResponseTimeChart')"
>
<div
v-for="name in checkOptions['ResponseTimeChart']"
:key="name"
>
<el-tooltip
class="item"
effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top"
>
<el-checkbox :label="name" />
</el-tooltip>
</div>
</el-checkbox-group>
@ -91,136 +134,212 @@
<el-collapse-item name="responseTimePercentiles">
<template v-slot:title>
<div style="width: 100%">
<span>{{ $t('load_test.report.ResponseTimePercentilesChart') }}</span>
<span style="float:right;">
<el-link type="primary" @click="selectAll( 'ResponseTimePercentilesChart', $event)">
{{ $t('load_test.report.select_all') }}
<span>{{
$t("load_test.report.ResponseTimePercentilesChart")
}}</span>
<span style="float: right">
<el-link
type="primary"
@click="selectAll('ResponseTimePercentilesChart', $event)"
>
{{ $t("load_test.report.select_all") }}
</el-link>
/
<el-link type="default" @click="unselectAll('ResponseTimePercentilesChart', $event)">
{{ $t('load_test.report.unselect_all') }}
<el-link
type="default"
@click="unselectAll('ResponseTimePercentilesChart', $event)"
>
{{ $t("load_test.report.unselect_all") }}
</el-link>
</span>
</div>
</template>
<el-checkbox-group v-model="checkList['ResponseTimePercentilesChart']"
@change="handleChecked('ResponseTimePercentilesChart')">
<div v-for="name in checkOptions['ResponseTimePercentilesChart']"
:key="name">
<el-tooltip class="item" effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top">
<el-checkbox :label="name"/>
<el-checkbox-group
v-model="checkList['ResponseTimePercentilesChart']"
@change="handleChecked('ResponseTimePercentilesChart')"
>
<div
v-for="name in checkOptions['ResponseTimePercentilesChart']"
:key="name"
>
<el-tooltip
class="item"
effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top"
>
<el-checkbox :label="name" />
</el-tooltip>
</div>
</el-checkbox-group>
</el-collapse-item>
<el-collapse-item :title="$t('load_test.report.ResponseCodeChart')" name="responseCode">
<el-collapse-item
:title="$t('load_test.report.ResponseCodeChart')"
name="responseCode"
>
<template v-slot:title>
<div style="width: 100%">
<span>{{ $t('load_test.report.ResponseCodeChart') }}</span>
<span style="float:right;">
<el-link type="primary" @click="selectAll( 'ResponseCodeChart', $event)">
{{ $t('load_test.report.select_all') }}
<span>{{ $t("load_test.report.ResponseCodeChart") }}</span>
<span style="float: right">
<el-link
type="primary"
@click="selectAll('ResponseCodeChart', $event)"
>
{{ $t("load_test.report.select_all") }}
</el-link>
/
<el-link type="default" @click="unselectAll('ResponseCodeChart', $event)">
{{ $t('load_test.report.unselect_all') }}
<el-link
type="default"
@click="unselectAll('ResponseCodeChart', $event)"
>
{{ $t("load_test.report.unselect_all") }}
</el-link>
</span>
</div>
</template>
<el-checkbox-group v-model="checkList['ResponseCodeChart']" @change="handleChecked('ResponseCodeChart')">
<div v-for="name in checkOptions['ResponseCodeChart']"
:key="name">
<el-tooltip class="item" effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top">
<el-checkbox :label="name"/>
<el-checkbox-group
v-model="checkList['ResponseCodeChart']"
@change="handleChecked('ResponseCodeChart')"
>
<div
v-for="name in checkOptions['ResponseCodeChart']"
:key="name"
>
<el-tooltip
class="item"
effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top"
>
<el-checkbox :label="name" />
</el-tooltip>
</div>
</el-checkbox-group>
</el-collapse-item>
<el-collapse-item :title="$t('load_test.report.LatencyChart')" name="latency">
<el-collapse-item
:title="$t('load_test.report.LatencyChart')"
name="latency"
>
<template v-slot:title>
<div style="width: 100%">
<span>{{ $t('load_test.report.LatencyChart') }}</span>
<span style="float:right;">
<el-link type="primary" @click="selectAll( 'LatencyChart', $event)">
{{ $t('load_test.report.select_all') }}
<span>{{ $t("load_test.report.LatencyChart") }}</span>
<span style="float: right">
<el-link
type="primary"
@click="selectAll('LatencyChart', $event)"
>
{{ $t("load_test.report.select_all") }}
</el-link>
/
<el-link type="default" @click="unselectAll('LatencyChart', $event)">
{{ $t('load_test.report.unselect_all') }}
<el-link
type="default"
@click="unselectAll('LatencyChart', $event)"
>
{{ $t("load_test.report.unselect_all") }}
</el-link>
</span>
</div>
</template>
<el-checkbox-group v-model="checkList['LatencyChart']" @change="handleChecked('LatencyChart')">
<div v-for="name in checkOptions['LatencyChart']"
:key="name">
<el-tooltip class="item" effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top">
<el-checkbox :label="name"/>
<el-checkbox-group
v-model="checkList['LatencyChart']"
@change="handleChecked('LatencyChart')"
>
<div v-for="name in checkOptions['LatencyChart']" :key="name">
<el-tooltip
class="item"
effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top"
>
<el-checkbox :label="name" />
</el-tooltip>
</div>
</el-checkbox-group>
</el-collapse-item>
<el-collapse-item :title="$t('load_test.report.BytesThroughputChart')" name="bytes">
<el-collapse-item
:title="$t('load_test.report.BytesThroughputChart')"
name="bytes"
>
<template v-slot:title>
<div style="width: 100%">
<span>{{ $t('load_test.report.BytesThroughputChart') }}</span>
<span style="float:right;">
<el-link type="primary" @click="selectAll( 'BytesThroughputChart', $event)">
{{ $t('load_test.report.select_all') }}
<span>{{ $t("load_test.report.BytesThroughputChart") }}</span>
<span style="float: right">
<el-link
type="primary"
@click="selectAll('BytesThroughputChart', $event)"
>
{{ $t("load_test.report.select_all") }}
</el-link>
/
<el-link type="default" @click="unselectAll('BytesThroughputChart', $event)">
{{ $t('load_test.report.unselect_all') }}
<el-link
type="default"
@click="unselectAll('BytesThroughputChart', $event)"
>
{{ $t("load_test.report.unselect_all") }}
</el-link>
</span>
</div>
</template>
<el-checkbox-group v-model="checkList['BytesThroughputChart']"
@change="handleChecked('BytesThroughputChart')">
<div v-for="name in checkOptions['BytesThroughputChart']"
:key="name">
<el-tooltip class="item" effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top">
<el-checkbox :label="name"/>
<el-checkbox-group
v-model="checkList['BytesThroughputChart']"
@change="handleChecked('BytesThroughputChart')"
>
<div
v-for="name in checkOptions['BytesThroughputChart']"
:key="name"
>
<el-tooltip
class="item"
effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top"
>
<el-checkbox :label="name" />
</el-tooltip>
</div>
</el-checkbox-group>
</el-collapse-item>
<el-collapse-item :title="$t('load_test.report.ErrorsChart')" name="errors">
<el-collapse-item
:title="$t('load_test.report.ErrorsChart')"
name="errors"
>
<template v-slot:title>
<div style="width: 100%">
<span>{{ $t('load_test.report.ErrorsChart') }}</span>
<span style="float:right;">
<el-link type="primary" @click="selectAll( 'ErrorsChart', $event)">
{{ $t('load_test.report.select_all') }}
<span>{{ $t("load_test.report.ErrorsChart") }}</span>
<span style="float: right">
<el-link
type="primary"
@click="selectAll('ErrorsChart', $event)"
>
{{ $t("load_test.report.select_all") }}
</el-link>
/
<el-link type="default" @click="unselectAll('ErrorsChart', $event)">
{{ $t('load_test.report.unselect_all') }}
<el-link
type="default"
@click="unselectAll('ErrorsChart', $event)"
>
{{ $t("load_test.report.unselect_all") }}
</el-link>
</span>
</div>
</template>
<el-checkbox-group v-model="checkList['ErrorsChart']" @change="handleChecked('ErrorsChart')">
<div v-for="name in checkOptions['ErrorsChart']"
:key="name">
<el-tooltip class="item" effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top">
<el-checkbox :label="name"/>
<el-checkbox-group
v-model="checkList['ErrorsChart']"
@change="handleChecked('ErrorsChart')"
>
<div v-for="name in checkOptions['ErrorsChart']" :key="name">
<el-tooltip
class="item"
effect="dark"
:content="name"
:disabled="name.length < minLength"
placement="top"
>
<el-checkbox :label="name" />
</el-tooltip>
</div>
</el-checkbox-group>
@ -230,12 +349,14 @@
<el-col :span="18" v-loading="result.loading">
<el-row>
<el-col :span="24">
<ms-chart ref="chart2"
v-if="refresh"
class="chart-config"
:options="totalOption"
@datazoom="changeDataZoom"
:autoresize="true"/>
<ms-chart
ref="chart2"
v-if="refresh"
class="chart-config"
:options="totalOption"
@datazoom="changeDataZoom"
:autoresize="true"
/>
</el-col>
</el-row>
<el-row>
@ -245,45 +366,20 @@
:data="tableData"
stripe
border
style="width: 100%">
style="width: 100%"
>
<el-table-column label="Label" align="center">
<el-table-column
prop="label"
label="Label"
sortable>
<el-table-column prop="label" label="Label" sortable>
</el-table-column>
</el-table-column>
<el-table-column label="Aggregate" align="center">
<el-table-column
prop="avg"
label="Avg."
width="100"
sortable
/>
<el-table-column
prop="min"
label="Min."
width="100"
sortable
/>
<el-table-column
prop="max"
label="Max."
width="100"
sortable
/>
<el-table-column prop="avg" label="Avg." width="100" sortable />
<el-table-column prop="min" label="Min." width="100" sortable />
<el-table-column prop="max" label="Max." width="100" sortable />
</el-table-column>
<el-table-column label="Range" align="center">
<el-table-column
prop="startTime"
label="Start"
width="160"
/>
<el-table-column
prop="endTime"
label="End"
width="160"
/>
<el-table-column prop="startTime" label="Start" width="160" />
<el-table-column prop="endTime" label="End" width="160" />
</el-table-column>
</el-table>
</el-col>
@ -296,7 +392,19 @@
<script>
import MsChart from "metersphere-frontend/src/components/chart/MsChart";
const color = ['#60acfc', '#32d3eb', '#5bc49f', '#feb64d', '#ff7c7c', '#9287e7', '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'];
const color = [
"#60acfc",
"#32d3eb",
"#5bc49f",
"#feb64d",
"#ff7c7c",
"#9287e7",
"#ca8622",
"#bda29a",
"#6e7074",
"#546570",
"#c4ccd3",
];
const groupBy = function (xs, key) {
return xs.reduce(function (rv, x) {
@ -306,24 +414,24 @@ const groupBy = function (xs, key) {
};
const CHART_MAP = [
'ActiveThreadsChart',
'TransactionsChart',
'ResponseTimeChart',
'ResponseTimePercentilesChart',
'ResponseCodeChart',
'ErrorsChart',
'LatencyChart',
'BytesThroughputChart',
"ActiveThreadsChart",
"TransactionsChart",
"ResponseTimeChart",
"ResponseTimePercentilesChart",
"ResponseCodeChart",
"ErrorsChart",
"LatencyChart",
"BytesThroughputChart",
];
export default {
name: "TestDetails",
components: {MsChart},
props: ['report', 'export', 'isShare', 'shareId', 'planReportTemplate'],
components: { MsChart },
props: ["report", "export", "isShare", "shareId", "planReportTemplate"],
data() {
return {
result: {},
activeNames: 'users',
activeNames: "users",
minLength: 35,
loadOption: {},
resOption: {},
@ -335,8 +443,8 @@ export default {
}, {}),
checkOptions: {},
defaultProps: {
children: 'children',
label: 'label'
children: "children",
label: "label",
},
init: false,
refresh: true,
@ -349,9 +457,9 @@ export default {
title: {},
tooltip: {
show: true,
trigger: 'axis',
trigger: "axis",
axisPointer: {
type: 'cross'
type: "cross",
},
confine: true,
formatter: function (params, ticket, callback) {
@ -369,41 +477,43 @@ export default {
}
return result;
}
},
},
legend: {
y: 'top',
y: "top",
},
xAxis: {boundaryGap: false},
xAxis: { boundaryGap: false },
yAxis: [],
dataZoom: [
{
type: 'inside',
type: "inside",
start: 0,
end: 100
end: 100,
},
{
start: 0,
end: 20
}
end: 20,
},
],
series: []
series: [],
},
seriesData: [],
legend: [],
};
},
created() {
this.initTableData();
},
methods: {
resetDefault() {
this.checkList['ActiveThreadsChart'] = ['ALL'];
this.checkList['TransactionsChart'] = ['ALL'];
this.checkList['ResponseTimeChart'] = ['ALL'];
this.checkList["ActiveThreadsChart"] = ["ALL"];
this.checkList["TransactionsChart"] = ["ALL"];
this.checkList["ResponseTimeChart"] = ["ALL"];
//
this.checkList['ResponseTimePercentilesChart'] = [];
this.checkList['ErrorsChart'] = [];
this.checkList['LatencyChart'] = [];
this.checkList['BytesThroughputChart'] = [];
this.checkList["ResponseTimePercentilesChart"] = [];
this.checkList["ErrorsChart"] = [];
this.checkList["LatencyChart"] = [];
this.checkList["BytesThroughputChart"] = [];
this.getTotalChart();
},
@ -437,7 +547,6 @@ export default {
}
},
handleChecked(name) {
this.getTotalChart();
this.refresh = false;
@ -463,9 +572,11 @@ export default {
this.init = false;
return;
}
let yAxisIndex0List = data.filter(m => m.yAxis2 === -1).map(m => m.groupName);
let yAxisIndex0List = data
.filter((m) => m.yAxis2 === -1)
.map((m) => m.groupName);
yAxisIndex0List = this._unique(yAxisIndex0List);
this.checkOptions[reportKey] = ['ALL'].concat(yAxisIndex0List);
this.checkOptions[reportKey] = ["ALL"].concat(yAxisIndex0List);
},
getTotalChart() {
this.result.loading = true;
@ -479,22 +590,24 @@ export default {
let chars = [];
for (let name in this.checkList) {
let data = this.planReportTemplate.checkOptions[name];
chars.push({data, 'reportKey': name});
chars.push({ data, reportKey: name });
}
this.handleGetTotalChart(chars);
} else {
for (let name in this.checkList) {
promises.push(this.getChart(name, this.checkList[name]));
}
Promise.all(promises).then((res) => {
this.handleGetTotalChart(res);
}).catch(() => {
this.result.loading = false;
});
Promise.all(promises)
.then((res) => {
this.handleGetTotalChart(res);
})
.catch(() => {
this.result.loading = false;
});
}
},
handleGetTotalChart(res) {
res = res.filter(v => !!v);
res = res.filter((v) => !!v);
if (res.length === 0) {
this.refresh = false;
this.result.loading = false;
@ -504,27 +617,27 @@ export default {
for (let i = 0; i < res.length; i++) {
if (i === 0) {
this.baseOption.yAxis.push({
name: this.$t('load_test.report.' + res[i].reportKey),
type: 'value',
name: this.$t("load_test.report." + res[i].reportKey),
type: "value",
min: 0,
position: 'left',
boundaryGap: [0, '100%']
position: "left",
boundaryGap: [0, "100%"],
});
} else {
this.baseOption.yAxis.push({
name: this.$t('load_test.report.' + res[i].reportKey),
type: 'value',
name: this.$t("load_test.report." + res[i].reportKey),
type: "value",
min: 0,
position: 'right',
position: "right",
nameRotate: 20,
offset: (i - 1) * 50,
boundaryGap: [0, '100%']
boundaryGap: [0, "100%"],
});
}
this.totalOption = this.generateOption(this.baseOption, res[i].data, i);
}
this.totalOption.grid.right = (res.length - 1) * 5 + '%';
this.changeDataZoom({start: 0, end: 100});
this.totalOption.grid.right = (res.length - 1) * 5 + "%";
this.changeDataZoom({ start: 0, end: 100 });
this.result.loading = false;
},
getChart(reportKey, checkList) {
@ -535,29 +648,31 @@ export default {
},
handleGetChart(data, reportKey, checkList) {
let allData = [];
let checkAllOption = checkList.indexOf('ALL') > -1;
let checkAllOption = checkList.indexOf("ALL") > -1;
if (checkAllOption) {
let avgOpt = [
'ResponseTimeChart',
'ResponseTimePercentilesChart',
'LatencyChart',
"ResponseTimeChart",
"ResponseTimePercentilesChart",
"LatencyChart",
];
let result = groupBy(data, 'xAxis');
let result = groupBy(data, "xAxis");
for (const xAxis in result) {
let yAxis = result[xAxis].map(a => a.yAxis).reduce((a, b) => a + b, 0);
let yAxis = result[xAxis]
.map((a) => a.yAxis)
.reduce((a, b) => a + b, 0);
if (avgOpt.indexOf(reportKey) > -1) {
yAxis = yAxis / result[xAxis].length;
}
allData.push({
groupName: 'ALL',
groupName: "ALL",
xAxis: xAxis,
yAxis: yAxis
yAxis: yAxis,
});
}
}
//
data = data.filter(item => {
data = data.filter((item) => {
if (checkList.indexOf(item.groupName) > -1) {
return true;
}
@ -566,17 +681,18 @@ export default {
// all
data = data.concat(allData);
// prefix
data.forEach(item => {
item.groupName = this.$t('load_test.report.' + reportKey) + ': ' + item.groupName;
data.forEach((item) => {
item.groupName =
this.$t("load_test.report." + reportKey) + ": " + item.groupName;
});
return {data, reportKey};
return { data, reportKey };
},
generateOption(option, data, yAxisIndex) {
let chartData = data;
let series = {}, xAxis = [];
chartData.forEach(item => {
let series = {},
xAxis = [];
chartData.forEach((item) => {
if (!xAxis.includes(item.xAxis)) {
xAxis.push(item.xAxis);
}
@ -587,9 +703,11 @@ export default {
series[name] = [];
}
if (series[name]) {
series[name].splice(xAxis.indexOf(item.xAxis), 0, [item.xAxis, item.yAxis.toFixed(2)]);
series[name].splice(xAxis.indexOf(item.xAxis), 0, [
item.xAxis,
item.yAxis.toFixed(2),
]);
}
});
this.$set(option.legend, "data", this.legend);
this.$set(option.legend, "type", "scroll");
@ -600,11 +718,11 @@ export default {
d.sort((a, b) => a[0].localeCompare(b[0]));
let items = {
name: name,
type: 'line',
type: "line",
data: d,
yAxisIndex: yAxisIndex,
smooth: true,
sampling: 'lttb',
sampling: "lttb",
showSymbol: false,
animation: !this.export,
};
@ -623,9 +741,15 @@ export default {
let tableData = [];
for (let i = 0; i < this.seriesData.length; i++) {
let sub = this.seriesData[i].data, label = this.seriesData[i].name;
let sub = this.seriesData[i].data,
label = this.seriesData[i].name;
let len = 0;
let min, avg, max, sum = 0, startTime, endTime;
let min,
avg,
max,
sum = 0,
startTime,
endTime;
for (let j = 0; j < sub.length; j++) {
let time = sub[j][0];
let value = Number.parseFloat(sub[j][1]);
@ -658,7 +782,7 @@ export default {
}
avg = (sum / len).toFixed(2);
tableData.push({label, min, max, avg, startTime, endTime});
tableData.push({ label, min, max, avg, startTime, endTime });
}
this.tableData = tableData;
},
@ -668,12 +792,12 @@ export default {
},
_unique(arr) {
return Array.from(new Set(arr));
}
},
},
watch: {
'$route'(to) {
$route(to) {
if (to.name === "perReportView") {
this.id = to.path.split('/')[4];
this.id = to.path.split("/")[4];
this.init = false;
this.initTableData();
}
@ -694,7 +818,7 @@ export default {
this.initTableData();
}
},
deep: true
deep: true,
},
planReportTemplate: {
handler() {
@ -704,10 +828,9 @@ export default {
// this.getTotalChart();
}
},
deep: true
}
deep: true,
},
},
};
</script>
@ -722,7 +845,7 @@ export default {
overflow: auto;
}
:deep(.el-checkbox__label ) {
:deep(.el-checkbox__label) {
font-size: 10px !important;
}
</style>

View File

@ -7,7 +7,9 @@
<span class="ms-card-data-digital">{{ maxUsers }}</span>
<span class="ms-card-data-unit"> VU</span>
</span>
<span class="ms-card-desc">{{ $t('load_test.report.ActiveThreadsChart') }}</span>
<span class="ms-card-desc">{{
$t("load_test.report.ActiveThreadsChart")
}}</span>
</el-card>
</el-col>
<el-col :span="4">
@ -16,7 +18,9 @@
<span class="ms-card-data-digital">{{ avgTransactions }}</span>
<span class="ms-card-data-unit"> TPS</span>
</span>
<span class="ms-card-desc">{{ $t('load_test.report.TransactionsChart') }}</span>
<span class="ms-card-desc">{{
$t("load_test.report.TransactionsChart")
}}</span>
</el-card>
</el-col>
<el-col :span="4">
@ -25,7 +29,9 @@
<span class="ms-card-data-digital">{{ errors }}</span>
<span class="ms-card-data-unit"> %</span>
</span>
<span class="ms-card-desc">{{ $t('load_test.report.ErrorsChart') }}</span>
<span class="ms-card-desc">{{
$t("load_test.report.ErrorsChart")
}}</span>
</el-card>
</el-col>
<el-col :span="4">
@ -34,7 +40,9 @@
<span class="ms-card-data-digital">{{ avgResponseTime }}</span>
<span class="ms-card-data-unit"> s</span>
</span>
<span class="ms-card-desc">{{ $t('load_test.report.ResponseTimeChart') }}</span>
<span class="ms-card-desc">{{
$t("load_test.report.ResponseTimeChart")
}}</span>
</el-card>
</el-col>
<el-col :span="4">
@ -43,7 +51,9 @@
<span class="ms-card-data-digital">{{ responseTime90 }}</span>
<span class="ms-card-data-unit"> s</span>
</span>
<span class="ms-card-desc">90% {{ $t('load_test.report.ResponseTimeChart') }}</span>
<span class="ms-card-desc"
>90% {{ $t("load_test.report.ResponseTimeChart") }}</span
>
</el-card>
</el-col>
<el-col :span="4">
@ -52,17 +62,27 @@
<span class="ms-card-data-digital">{{ avgBandwidth }}</span>
<span class="ms-card-data-unit"> KiB/s</span>
</span>
<span class="ms-card-desc">{{ $t('load_test.report.Network') }}</span>
<span class="ms-card-desc">{{ $t("load_test.report.Network") }}</span>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<ms-chart ref="chart1" :options="loadOption" class="chart-config" :autoresize="true"></ms-chart>
<ms-chart
ref="chart1"
:options="loadOption"
class="chart-config"
:autoresize="true"
></ms-chart>
</el-col>
<el-col :span="12">
<ms-chart ref="chart2" :options="resOption" class="chart-config" :autoresize="true"></ms-chart>
<ms-chart
ref="chart2"
:options="resOption"
class="chart-config"
:autoresize="true"
></ms-chart>
</el-col>
</el-row>
</div>
@ -71,7 +91,19 @@
<script>
import MsChart from "metersphere-frontend/src/components/chart/MsChart";
const color = ['#60acfc', '#32d3eb', '#5bc49f', '#feb64d', '#ff7c7c', '#9287e7', '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'];
const color = [
"#60acfc",
"#32d3eb",
"#5bc49f",
"#feb64d",
"#ff7c7c",
"#9287e7",
"#ca8622",
"#bda29a",
"#6e7074",
"#546570",
"#c4ccd3",
];
const groupBy = function (xs, key) {
return xs.reduce(function (rv, x) {
@ -82,7 +114,7 @@ const groupBy = function (xs, key) {
export default {
name: "TestOverview",
components: {MsChart},
components: { MsChart },
data() {
return {
maxUsers: "0",
@ -96,10 +128,13 @@ export default {
resOption: {},
errorOption: {},
resCodeOption: {},
id: ''
id: "",
};
},
props: ['report', 'export', 'isShare', 'shareId', 'planReportTemplate'],
props: ["report", "export", "isShare", "shareId", "planReportTemplate"],
created() {
this.initTableData();
},
methods: {
initTableData() {
if (this.planReportTemplate) {
@ -110,13 +145,13 @@ export default {
this.getResChart();
},
buildInfo(data) {
this.maxUsers = data ? data.maxUsers : '0';
this.avgThroughput = data ? data.avgThroughput : '0';
this.avgTransactions = data ? data.avgTransactions : '0';
this.errors = data ? data.errors : '0';
this.avgResponseTime = data ? data.avgResponseTime : '0';
this.responseTime90 = data ? data.responseTime90 : '0';
this.avgBandwidth = data ? data.avgBandwidth : '0';
this.maxUsers = data ? data.maxUsers : "0";
this.avgThroughput = data ? data.avgThroughput : "0";
this.avgTransactions = data ? data.avgTransactions : "0";
this.errors = data ? data.errors : "0";
this.avgResponseTime = data ? data.avgResponseTime : "0";
this.responseTime90 = data ? data.responseTime90 : "0";
this.avgBandwidth = data ? data.avgBandwidth : "0";
},
getLoadChart() {
if (this.planReportTemplate) {
@ -131,63 +166,77 @@ export default {
let loadOption = {
color: color,
title: {
text: 'Load',
left: 'center',
text: "Load",
left: "center",
top: 20,
textStyle: {
color: '#65A2FF'
color: "#65A2FF",
},
},
tooltip: {
show: true,
trigger: 'axis',
trigger: "axis",
// extraCssText: 'z-index: 999;',
confine: true,
},
legend: {},
xAxis: {},
series: []
series: [],
};
let allData = [];
let result = groupBy(data, 'xAxis');
let result = groupBy(data, "xAxis");
for (const xAxis in result) {
let yAxis1 = result[xAxis].filter(a => a.yAxis2 === -1).map(a => a.yAxis).reduce((a, b) => a + b, 0);
let yAxis2 = result[xAxis].filter(a => a.yAxis === -1).map(a => a.yAxis2).reduce((a, b) => a + b, 0);
allData.push({
groupName: 'users',
xAxis: xAxis,
yAxis: yAxis1,
yAxis2: -1,
yAxisIndex: 0,
}, {
groupName: 'transactions/s',
xAxis: xAxis,
yAxis: -1,
yAxis2: yAxis2,
yAxisIndex: 1,
});
let yAxis1 = result[xAxis]
.filter((a) => a.yAxis2 === -1)
.map((a) => a.yAxis)
.reduce((a, b) => a + b, 0);
let yAxis2 = result[xAxis]
.filter((a) => a.yAxis === -1)
.map((a) => a.yAxis2)
.reduce((a, b) => a + b, 0);
allData.push(
{
groupName: "users",
xAxis: xAxis,
yAxis: yAxis1,
yAxis2: -1,
yAxisIndex: 0,
},
{
groupName: "transactions/s",
xAxis: xAxis,
yAxis: -1,
yAxis2: yAxis2,
yAxisIndex: 1,
}
);
}
let yAxisList = allData.filter(m => m.yAxis2 === -1).map(m => m.yAxis);
let yAxis2List = allData.filter(m => m.yAxis === -1).map(m => m.yAxis2);
let yAxisList = allData
.filter((m) => m.yAxis2 === -1)
.map((m) => m.yAxis);
let yAxis2List = allData
.filter((m) => m.yAxis === -1)
.map((m) => m.yAxis2);
let yAxisListMax = this._getChartMax(yAxisList);
let yAxis2ListMax = this._getChartMax(yAxis2List);
loadOption.yAxis = [{
name: 'User',
type: 'value',
min: 0,
max: yAxisListMax,
splitNumber: 5,
interval: yAxisListMax / 5
},
loadOption.yAxis = [
{
name: 'Transactions/s',
type: 'value',
name: "User",
type: "value",
min: 0,
max: yAxisListMax,
splitNumber: 5,
interval: yAxisListMax / 5,
},
{
name: "Transactions/s",
type: "value",
splitNumber: 5,
min: 0,
max: yAxis2ListMax,
interval: yAxis2ListMax / 5
}
interval: yAxis2ListMax / 5,
},
];
this.loadOption = this.generateOption(loadOption, allData);
},
@ -204,16 +253,16 @@ export default {
let resOption = {
color: color,
title: {
text: 'Response Time',
left: 'center',
text: "Response Time",
left: "center",
top: 20,
textStyle: {
color: '#99743C'
color: "#99743C",
},
},
tooltip: {
show: true,
trigger: 'axis',
trigger: "axis",
// extraCssText: 'z-index: 999;',
confine: true,
formatter: function (params, ticket, callback) {
@ -231,21 +280,24 @@ export default {
}
return result;
}
},
},
legend: {},
xAxis: {},
series: []
series: [],
};
let allData = [];
let result = groupBy(data, 'xAxis');
let result = groupBy(data, "xAxis");
for (const xAxis in result) {
let yAxis1 = result[xAxis].filter(a => a.yAxis2 === -1).map(a => a.yAxis).reduce((a, b) => a + b, 0);
let yAxis1 = result[xAxis]
.filter((a) => a.yAxis2 === -1)
.map((a) => a.yAxis)
.reduce((a, b) => a + b, 0);
yAxis1 = yAxis1 / result[xAxis].length;
allData.push({
groupName: 'response',
groupName: "response",
xAxis: xAxis,
yAxis: -1,
yAxis2: yAxis1,
@ -253,16 +305,18 @@ export default {
});
}
let yAxisList = allData.filter(m => m.yAxis === -1).map(m => m.yAxis2);
let yAxisList = allData
.filter((m) => m.yAxis === -1)
.map((m) => m.yAxis2);
let yAxisListMax = this._getChartMax(yAxisList);
resOption.yAxis = [
{
name: 'Response Time',
type: 'value',
name: "Response Time",
type: "value",
min: 0,
max: yAxisListMax,
interval: yAxisListMax / 5
}
interval: yAxisListMax / 5,
},
];
this.resOption = this.generateOption(resOption, allData);
},
@ -279,16 +333,16 @@ export default {
let errorOption = {
color: color,
title: {
text: 'Errors',
left: 'center',
text: "Errors",
left: "center",
top: 20,
textStyle: {
color: '#99743C'
color: "#99743C",
},
},
tooltip: {
show: true,
trigger: 'axis',
trigger: "axis",
// extraCssText: 'z-index: 999;',
confine: true,
formatter: function (params, ticket, callback) {
@ -306,36 +360,41 @@ export default {
}
return result;
}
},
},
legend: {},
xAxis: {},
series: []
series: [],
};
let allData = [];
let result = groupBy(data, 'xAxis');
let result = groupBy(data, "xAxis");
for (const xAxis in result) {
let yAxis1 = result[xAxis].filter(a => a.yAxis2 === -1).map(a => a.yAxis).reduce((a, b) => a + b, 0);
let yAxis1 = result[xAxis]
.filter((a) => a.yAxis2 === -1)
.map((a) => a.yAxis)
.reduce((a, b) => a + b, 0);
allData.push({
groupName: 'errors',
groupName: "errors",
xAxis: xAxis,
yAxis: -1,
yAxis2: yAxis1,
yAxisIndex: 0,
});
}
let yAxisList = allData.filter(m => m.yAxis === -1).map(m => m.yAxis2);
let yAxisList = allData
.filter((m) => m.yAxis === -1)
.map((m) => m.yAxis2);
let yAxisListMax = this._getChartMax(yAxisList);
errorOption.yAxis = [
{
name: 'No',
type: 'value',
name: "No",
type: "value",
min: 0,
max: yAxisListMax,
interval: yAxisListMax / 5
}
interval: yAxisListMax / 5,
},
];
this.errorOption = this.generateOption(errorOption, allData);
@ -353,16 +412,16 @@ export default {
let resCodeOption = {
color: color,
title: {
text: 'Response code',
left: 'center',
text: "Response code",
left: "center",
top: 20,
textStyle: {
color: '#99743C'
color: "#99743C",
},
},
tooltip: {
show: true,
trigger: 'axis',
trigger: "axis",
// extraCssText: 'z-index: 999;',
confine: true,
formatter: function (params, ticket, callback) {
@ -380,43 +439,52 @@ export default {
}
return result;
}
},
},
legend: {},
xAxis: {},
series: []
series: [],
};
let allData = [];
let result = groupBy(data, 'xAxis');
let result = groupBy(data, "xAxis");
for (const xAxis in result) {
let yAxis1 = result[xAxis].filter(a => a.yAxis2 === -1).map(a => a.yAxis).reduce((a, b) => a + b, 0);
let yAxis1 = result[xAxis]
.filter((a) => a.yAxis2 === -1)
.map((a) => a.yAxis)
.reduce((a, b) => a + b, 0);
allData.push({
groupName: 'codes',
groupName: "codes",
xAxis: xAxis,
yAxis: -1,
yAxis2: yAxis1,
yAxisIndex: 0,
});
}
let yAxisList = allData.filter(m => m.yAxis === -1).map(m => m.yAxis2);
let yAxisList = allData
.filter((m) => m.yAxis === -1)
.map((m) => m.yAxis2);
let yAxisListMax = this._getChartMax(yAxisList);
resCodeOption.yAxis = [
{
name: 'No',
type: 'value',
name: "No",
type: "value",
min: 0,
max: yAxisListMax,
interval: yAxisListMax / 5
}
interval: yAxisListMax / 5,
},
];
this.resCodeOption = this.generateOption(resCodeOption, allData);
},
generateOption(option, data) {
let chartData = data;
let legend = [], series = {}, xAxis = [], seriesData = [], yAxisIndex = {};
chartData.forEach(item => {
let legend = [],
series = {},
xAxis = [],
seriesData = [],
yAxisIndex = {};
chartData.forEach((item) => {
if (!xAxis.includes(item.xAxis)) {
xAxis.push(item.xAxis);
}
@ -428,9 +496,15 @@ export default {
series[name] = [];
}
if (item.yAxis === -1) {
series[name].splice(xAxis.indexOf(item.xAxis), 0, [item.xAxis, item.yAxis2.toFixed(2)]);
series[name].splice(xAxis.indexOf(item.xAxis), 0, [
item.xAxis,
item.yAxis2.toFixed(2),
]);
} else {
series[name].splice(xAxis.indexOf(item.xAxis), 0, [item.xAxis, item.yAxis.toFixed(2)]);
series[name].splice(xAxis.indexOf(item.xAxis), 0, [
item.xAxis,
item.yAxis.toFixed(2),
]);
}
});
this.$set(option.legend, "data", legend);
@ -442,13 +516,13 @@ export default {
d.sort((a, b) => a[0].localeCompare(b[0]));
let items = {
name: name,
type: 'line',
type: "line",
data: d,
smooth: true,
sampling: 'lttb',
sampling: "lttb",
showSymbol: false,
animation: !this.export,
yAxisIndex: yAxisIndex[name]
yAxisIndex: yAxisIndex[name],
};
seriesData.push(items);
}
@ -461,7 +535,7 @@ export default {
},
_unique(arr) {
return Array.from(new Set(arr));
}
},
},
watch: {
report: {
@ -474,20 +548,20 @@ export default {
if (status === "Completed" || status === "Running") {
this.initTableData();
} else {
this.maxUsers = '0';
this.avgThroughput = '0';
this.avgTransactions = '0';
this.errors = '0';
this.avgResponseTime = '0';
this.responseTime90 = '0';
this.avgBandwidth = '0';
this.maxUsers = "0";
this.avgThroughput = "0";
this.avgTransactions = "0";
this.errors = "0";
this.avgResponseTime = "0";
this.responseTime90 = "0";
this.avgBandwidth = "0";
this.loadOption = {};
this.resOption = {};
this.errorOption = {};
this.resCodeOption = {};
}
},
deep: true
deep: true,
},
planReportTemplate: {
handler() {
@ -495,14 +569,13 @@ export default {
this.initTableData();
}
},
deep: true
}
deep: true,
},
},
};
</script>
<style scoped>
.ms-card-data {
text-align: left;
display: block;
@ -533,52 +606,51 @@ export default {
}
.ms-card-index-2 .ms-card-data-digital {
color: #65A2FF;
color: #65a2ff;
}
.ms-card-index-2 {
border-left-color: #65A2FF;
border-left-color: #65a2ff;
border-left-width: 3px;
}
.ms-card-index-3 .ms-card-data-digital {
color: #E6113C;
color: #e6113c;
}
.ms-card-index-3 {
border-left-color: #E6113C;
border-left-color: #e6113c;
border-left-width: 3px;
}
.ms-card-index-4 .ms-card-data-digital {
color: #99743C;
color: #99743c;
}
.ms-card-index-4 {
border-left-color: #99743C;
border-left-color: #99743c;
border-left-width: 3px;
}
.ms-card-index-5 .ms-card-data-digital {
color: #99743C;
color: #99743c;
}
.ms-card-index-5 {
border-left-color: #99743C;
border-left-color: #99743c;
border-left-width: 3px;
}
.ms-card-index-6 .ms-card-data-digital {
color: #3C9899;
color: #3c9899;
}
.ms-card-index-6 {
border-left-color: #3C9899;
border-left-color: #3c9899;
border-left-width: 3px;
}
.chart-config {
width: 100%;
}
</style>