refactor(性能测试): 报告页面显示更多内容

This commit is contained in:
CaptainB 2021-11-18 19:02:49 +08:00 committed by 刘瑞斌
parent 7a23956f63
commit 4439b17ae0
6 changed files with 144 additions and 805 deletions

View File

@ -82,9 +82,6 @@
<el-divider/>
<div ref="resume">
<el-tabs v-model="active">
<el-tab-pane :label="$t('load_test.pressure_config')">
<ms-performance-pressure-config :is-read-only="true" :report="report"/>
</el-tab-pane>
<el-tab-pane :label="$t('report.test_overview')">
<ms-report-test-overview :report="report" ref="testOverview"/>
</el-tab-pane>
@ -103,6 +100,9 @@
<el-tab-pane :label="$t('report.test_monitor_details')">
<monitor-card :report="report"/>
</el-tab-pane>
<el-tab-pane :label="$t('测试配置')">
<ms-test-configuration :report="report" :test="test" :test-id="testId"/>
</el-tab-pane>
</el-tabs>
</div>
@ -131,7 +131,6 @@ import MsReportLogDetails from './components/LogDetails';
import MsReportRequestStatistics from './components/RequestStatistics';
import MsReportTestDetails from './components/TestDetails';
import MsReportTestOverview from './components/TestOverview';
import MsPerformancePressureConfig from "./components/PerformancePressureConfig";
import MsContainer from "../../common/components/MsContainer";
import MsMainContainer from "../../common/components/MsMainContainer";
@ -141,11 +140,13 @@ import MsPerformanceReportExport from "./PerformanceReportExport";
import {Message} from "element-ui";
import SameTestReports from "@/business/components/performance/report/components/SameTestReports";
import MonitorCard from "@/business/components/performance/report/components/MonitorCard";
import MsTestConfiguration from "@/business/components/performance/report/components/TestConfiguration";
export default {
name: "PerformanceReportView",
components: {
MsTestConfiguration,
MonitorCard,
SameTestReports,
MsPerformanceReportExport,
@ -156,7 +157,6 @@ export default {
MsContainer,
MsMainContainer,
MsReportTestDetails,
MsPerformancePressureConfig
},
props: {
perReportId: String
@ -164,7 +164,7 @@ export default {
data() {
return {
result: {},
active: '1',
active: '0',
reportId: '',
status: '',
reportName: '',
@ -182,7 +182,7 @@ export default {
websocket: null,
dialogFormVisible: false,
reportExportVisible: false,
testPlan: {testResourcePoolId: null},
test: {testResourcePoolId: null},
refreshTime: localStorage.getItem("reportRefreshTime") || "10",
refreshTimes: [
{value: '1', label: '1s'},
@ -414,6 +414,7 @@ export default {
if (data) {
this.status = data.status;
this.$set(this, "report", data);
this.$set(this.test, "testResourcePoolId", data.testResourcePoolId);
this.checkReportStatus(data.status);
if (this.status === "Completed" || this.status === "Running") {
this.initReportTimeInfo();

View File

@ -1,695 +0,0 @@
<template>
<div v-loading="result.loading" class="pressure-config-container">
<el-row>
<el-col :span="12">
<el-collapse v-model="activeNames" accordion>
<el-collapse-item :name="index"
v-for="(threadGroup, index) in threadGroups.filter(th=>th.enabled === 'true' && th.deleted=='false')"
:key="index">
<template slot="title">
<el-row>
<el-col :span="14">
<el-tooltip :content="threadGroup.attributes.testname" placement="top">
<div style="padding-right:20px; font-size: 16px;" class="wordwrap">
{{ threadGroup.attributes.testname }}
</div>
</el-tooltip>
</el-col>
<el-col :span="10">
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'DURATION'">
{{ $t('load_test.thread_num') }}{{ threadGroup.threadNumber }},
{{ $t('load_test.duration') }}:
<span v-if="threadGroup.durationHours">
{{ threadGroup.durationHours }}{{ $t('schedule.cron.hours') }}
</span>
<span v-if="threadGroup.durationMinutes">
{{ threadGroup.durationMinutes }}{{ $t('schedule.cron.minutes') }}
</span>
<span v-if="threadGroup.durationSeconds">
{{ threadGroup.durationSeconds }}{{ $t('schedule.cron.seconds') }}
</span>
</el-tag>
<el-tag type="primary" size="mini" v-if="threadGroup.threadType === 'ITERATION'">
{{ $t('load_test.thread_num') }} {{ threadGroup.threadNumber }},
{{ $t('load_test.iterate_num') }} {{ threadGroup.iterateNum }}
</el-tag>
</el-col>
</el-row>
</template>
<el-form :inline="true" label-width="100px">
<el-form-item :label="$t('load_test.thread_num')">
<el-input-number
:disabled="true"
:placeholder="$t('load_test.input_thread_num')"
v-model="threadGroup.threadNumber"
:min="1"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.run_mode')">
<el-radio-group v-model="threadGroup.threadType" size="mini" :disabled="true">
<el-radio-button label="DURATION">{{ $t('load_test.by_duration') }}</el-radio-button>
<el-radio-button label="ITERATION">{{ $t('load_test.by_iteration') }}</el-radio-button>
</el-radio-group>
</el-form-item>
<br>
<div v-if="threadGroup.threadType === 'DURATION'">
<el-form-item :label="$t('load_test.duration')">
<el-input-number controls-position="right"
:disabled="true"
v-model="threadGroup.durationHours"
:min="0"
:max="9999"
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('schedule.cron.hours')" label-width="40px"/>
<el-form-item>
<el-input-number controls-position="right"
:disabled="true"
v-model="threadGroup.durationMinutes"
:min="0"
:max="59"
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('schedule.cron.minutes')" label-width="40px"/>
<el-form-item>
<el-input-number controls-position="right"
:disabled="true"
v-model="threadGroup.durationSeconds"
:min="0"
:max="59"
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
<el-form-item :label="$t('schedule.cron.seconds')" label-width="20px"/>
<br>
<el-form-item :label="$t('load_test.rps_limit_enable')">
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
</el-form-item>
<el-form-item :label="$t('load_test.rps_limit')">
<el-input-number controls-position="right"
:disabled="true || !threadGroup.rpsLimitEnable"
v-model="threadGroup.rpsLimit"
@change="calculateTotalChart()"
:min="1"
:max="99999"
size="mini"/>
</el-form-item>
<div v-if="threadGroup.tgType === 'com.blazemeter.jmeter.threads.concurrency.ConcurrencyThreadGroup'">
<el-form-item label="Ramp-Up">
<el-input-number controls-position="right"
:disabled="true"
:min="1"
:max="getDuration(threadGroup)"
v-model="threadGroup.rampUpTime"
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
<el-form-item label="Step" label-width="50px">
<el-input-number controls-position="right"
:disabled="true"
:min="1"
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
v-model="threadGroup.step"
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
</div>
<div v-if="threadGroup.tgType === 'ThreadGroup'">
<el-form-item label="Ramp-Up">
<el-input-number controls-position="right"
:disabled="true"
:min="1"
:max="getDuration(threadGroup)"
v-model="threadGroup.rampUpTime"
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
</div>
</div>
<div v-if="threadGroup.threadType === 'ITERATION'">
<el-form-item :label="$t('load_test.iterate_num')">
<el-input-number controls-position="right"
:disabled="true"
v-model="threadGroup.iterateNum"
:min="1"
:max="9999999"
@change="calculateTotalChart()"
size="mini"/>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.rps_limit_enable')">
<el-switch v-model="threadGroup.rpsLimitEnable" @change="calculateTotalChart()"/>
</el-form-item>
<el-form-item :label="$t('load_test.rps_limit')">
<el-input-number controls-position="right"
:disabled="true || !threadGroup.rpsLimitEnable"
v-model="threadGroup.rpsLimit"
:min="1"
:max="99999"
size="mini"/>
</el-form-item>
<br>
<el-form-item label="Ramp-Up">
<el-input-number controls-position="right"
:disabled="true"
:min="1"
v-model="threadGroup.iterateRampUp"
size="mini"/>
</el-form-item>
</div>
<div v-if="resourcePoolType === 'NODE'">
<el-form-item :label="$t('load_test.resource_strategy')">
<el-radio-group v-model="threadGroup.strategy" :disabled="true" size="mini">
<el-radio-button label="auto">{{ $t('load_test.auto_ratio') }}</el-radio-button>
<el-radio-button label="specify">{{ $t('load_test.specify_resource') }}</el-radio-button>
<el-radio-button label="custom">{{ $t('load_test.custom_ratio') }}</el-radio-button>
</el-radio-group>
</el-form-item>
<div v-if="threadGroup.strategy === 'auto'"></div>
<div v-else-if="threadGroup.strategy === 'specify'">
<el-form-item :label="$t('load_test.specify_resource')">
<el-select v-model="threadGroup.resourceNodeIndex" :disabled="true" size="mini">
<el-option
v-for="(node, index) in resourceNodes"
:key="node.ip"
:label="node.ip"
:value="index">
</el-option>
</el-select>
</el-form-item>
</div>
<div v-else>
<el-table class="adjust-table" :data="threadGroup.resourceNodes" :max-height="200">
<el-table-column type="index" width="50"/>
<el-table-column prop="ip" label="IP"/>
<el-table-column prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"/>
<el-table-column prop="ratio" :label="$t('test_track.home.percentage')">
<template v-slot:default="{row}">
<el-input-number size="mini" v-model="row.ratio" :min="0" :step=".1" controls-position="right"
:max="1"></el-input-number>
</template>
</el-table-column>
</el-table>
</div>
</div>
</el-form>
</el-collapse-item>
</el-collapse>
</el-col>
<el-col :span="12">
<ms-chart class="chart-container" ref="chart1" :options="options" :autoresize="true"></ms-chart>
</el-col>
</el-row>
</div>
</template>
<script>
import MsChart from "@/business/components/common/chart/MsChart";
import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup";
import {
getOldPerformanceJmxContent,
getPerformanceJmxContent,
getPerformanceLoadConfig,
getPerformanceReport,
getShareOldPerformanceJmxContent,
getSharePerformanceJmxContent,
getSharePerformanceLoadConfig,
getSharePerformanceReport
} from "@/network/load-test";
const HANDLER = "handler";
const THREAD_GROUP_TYPE = "tgType";
const TARGET_LEVEL = "TargetLevel";
const RAMP_UP = "RampUp";
const STEPS = "Steps";
const DURATION = "duration";
const DURATION_HOURS = "durationHours";
const DURATION_MINUTES = "durationMinutes";
const DURATION_SECONDS = "durationSeconds";
const UNIT = "unit";
const RPS_LIMIT = "rpsLimit";
const RPS_LIMIT_ENABLE = "rpsLimitEnable";
const THREAD_TYPE = "threadType";
const ITERATE_NUM = "iterateNum";
const ITERATE_RAMP_UP = "iterateRampUpTime";
const ENABLED = "enabled";
const DELETED = "deleted";
const STRATEGY = "strategy";
const RESOURCE_NODE_INDEX = "resourceNodeIndex";
const RATIOS = "ratios";
const hexToRgb = function (hex) {
return 'rgb(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5))
+ ',' + parseInt('0x' + hex.slice(5, 7)) + ')';
};
export default {
name: "MsPerformancePressureConfig",
components: {MsChart},
props: ['report', 'isShare', 'shareId', 'planReportTemplate'],
data() {
return {
result: {},
threadNumber: 0,
duration: 0,
rampUpTime: 0,
step: 0,
rpsLimit: 0,
rpsLimitEnable: false,
options: {},
resourcePool: null,
resourcePools: [],
activeNames: ["0"],
threadGroups: [],
resourcePoolType: null,
resourceNodes: [],
};
},
activated() {
this.getJmxContent();
},
created() {
this.getResourcePools();
},
methods: {
getResourcePools() {
this.result = this.$get('/testresourcepool/list/quota/valid', response => {
this.resourcePools = response.data;
this.resourcePoolChange();
});
},
resourcePoolChange() {
let result = this.resourcePools.filter(p => p.id === this.report.testResourcePoolId);
if (result.length === 1) {
let threadNumber = 0;
this.resourceNodes = [];
this.resourcePoolType = result[0].type;
result[0].resources.forEach(resource => {
let config = JSON.parse(resource.configuration);
threadNumber += config.maxConcurrency;
this.resourceNodes.push(config);
});
this.threadGroups.forEach(tg => {
let tgRatios = tg.ratios;
let resourceNodes = JSON.parse(JSON.stringify(this.resourceNodes));
let ratios = resourceNodes.map(n => n.maxConcurrency).reduce((total, curr) => {
total += curr;
return total;
}, 0);
let preSum = 0;
for (let i = 0; i < resourceNodes.length; i++) {
let n = resourceNodes[i];
if (resourceNodes.length === tgRatios.length) {
n.ratio = tgRatios[i];
continue;
}
if (i === resourceNodes.length - 1) {
n.ratio = (1 - preSum).toFixed(2);
} else {
n.ratio = (n.maxConcurrency / ratios).toFixed(2);
preSum += Number.parseFloat(n.ratio);
}
}
this.$set(tg, "resourceNodes", resourceNodes);
if (tg.resourceNodeIndex > resourceNodes.length - 1) {
this.$set(tg, "resourceNodeIndex", 0);
}
});
this.calculateTotalChart();
}
},
calculateLoadConfiguration: function (data) {
for (let i = 0; i < this.threadGroups.length; i++) {
let d = data[i];
if (!d) {
return;
}
d.forEach(item => {
switch (item.key) {
case TARGET_LEVEL:
this.threadGroups[i].threadNumber = item.value;
break;
case RAMP_UP:
this.threadGroups[i].rampUpTime = item.value;
break;
case ITERATE_RAMP_UP:
this.threadGroups[i].iterateRampUp = item.value;
break;
case DURATION:
this.threadGroups[i].duration = item.value;
break;
case DURATION_HOURS:
this.threadGroups[i].durationHours = item.value;
break;
case DURATION_MINUTES:
this.threadGroups[i].durationMinutes = item.value;
break;
case DURATION_SECONDS:
this.threadGroups[i].durationSeconds = item.value;
break;
case UNIT:
this.threadGroups[i].unit = item.value;
break;
case STEPS:
this.threadGroups[i].step = item.value;
break;
case RPS_LIMIT:
this.threadGroups[i].rpsLimit = item.value;
break;
case RPS_LIMIT_ENABLE:
this.threadGroups[i].rpsLimitEnable = item.value;
break;
case THREAD_TYPE:
this.threadGroups[i].threadType = item.value;
break;
case ITERATE_NUM:
this.threadGroups[i].iterateNum = item.value;
break;
case ENABLED:
this.threadGroups[i].enabled = item.value;
break;
case DELETED:
this.threadGroups[i].deleted = item.value;
break;
case HANDLER:
this.threadGroups[i].handler = item.value;
break;
case THREAD_GROUP_TYPE:
this.threadGroups[i].tgType = item.value;
break;
case STRATEGY:
this.threadGroups[i].strategy = item.value;
break;
case RESOURCE_NODE_INDEX:
this.threadGroups[i].resourceNodeIndex = item.value;
break;
case RATIOS:
this.threadGroups[i].ratios = item.value;
break;
default:
break;
}
});
for (let i = 0; i < this.threadGroups.length; i++) {
let tg = this.threadGroups[i];
tg.durationHours = Math.floor(tg.duration / 3600);
tg.durationMinutes = Math.floor((tg.duration / 60 % 60));
tg.durationSeconds = Math.floor((tg.duration % 60));
}
this.resourcePoolChange();
this.calculateTotalChart();
}
},
getLoadConfig() {
if (!this.report.id && !this.planReportTemplate) {
return;
}
if (this.planReportTemplate) {
this.handleGetLoadConfig(this.planReportTemplate);
} else if (this.isShare) {
this.result = getSharePerformanceReport(this.shareId, this.report.id, data => {
this.handleGetLoadConfig(data);
});
} else {
this.result = getPerformanceReport(this.report.id, data => {
this.handleGetLoadConfig(data);
});
}
},
handleGetLoadConfig(data) {
if (data) {
if (data.loadConfiguration) {
let d = JSON.parse(data.loadConfiguration);
this.calculateLoadConfiguration(d);
} else {
if (this.planReportTemplate) {
if (this.planReportTemplate.loadConfig) {
let data = JSON.parse(this.planReportTemplate.fixLoadConfiguration);
this.calculateLoadConfiguration(data);
}
} else if (this.isShare) {
this.result = getSharePerformanceLoadConfig(this.shareId, this.report.id, data => {
if (data) {
data = JSON.parse(data);
this.calculateLoadConfiguration(data);
}
});
} else {
this.result = getPerformanceLoadConfig(this.report.id, data => {
if (data) {
data = JSON.parse(data);
this.calculateLoadConfiguration(data);
}
});
}
}
} else {
this.$error(this.$t('report.not_exist'));
}
},
getJmxContent() {
// console.log(this.report.testId);
if (!this.report.testId && !this.planReportTemplate) {
return;
}
if (this.planReportTemplate) {
if (this.planReportTemplate.jmxContent) {
this.handleGetJmxContent(JSON.parse(this.planReportTemplate.jmxContent));
}
} else if (this.isShare) {
this.result = getSharePerformanceJmxContent(this.shareId, this.report.id, data => {
this.handleGetJmxContent(data);
});
} else {
this.result = getPerformanceJmxContent(this.report.id, data => {
this.handleGetJmxContent(data);
});
}
},
handleGetJmxContent(d) {
if (!d) {
return;
}
let threadGroups = [];
threadGroups = threadGroups.concat(findThreadGroup(d.jmx, d.name));
threadGroups.forEach(tg => {
tg.options = {};
});
this.threadGroups = threadGroups;
this.getLoadConfig();
//
if (!threadGroups || threadGroups.length === 0) {
if (this.planReportTemplate) {
this.planReportTemplate.fixJmxContent.forEach(d => this.handleGetOldJmxContent(d, threadGroups));
} else if (this.isShare) {
this.result = getShareOldPerformanceJmxContent(this.shareId, this.report.testId, data => {
data.forEach(d => this.handleGetOldJmxContent(d, threadGroups));
});
} else {
this.result = getOldPerformanceJmxContent(this.report.testId, data => {
data.forEach(d => this.handleGetOldJmxContent(d, threadGroups));
});
}
}
},
handleGetOldJmxContent(d, threadGroups) {
threadGroups = threadGroups.concat(findThreadGroup(d.jmx, d.name));
threadGroups.forEach(tg => {
tg.options = {};
});
this.threadGroups = threadGroups;
this.getLoadConfig();
},
calculateTotalChart() {
let handler = this;
if (handler.duration < handler.rampUpTime) {
handler.rampUpTime = handler.duration;
}
if (handler.rampUpTime < handler.step) {
handler.step = handler.rampUpTime;
}
let color = ['#60acfc', '#32d3eb', '#5bc49f', '#feb64d', '#ff7c7c', '#9287e7', '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'];
handler.options = {
color: color,
xAxis: {
type: 'category',
boundaryGap: false,
data: []
},
yAxis: {
type: 'value'
},
tooltip: {
trigger: 'axis',
},
series: []
};
for (let i = 0; i < handler.threadGroups.length; i++) {
if (handler.threadGroups[i].enabled === 'false' ||
handler.threadGroups[i].deleted === 'true' ||
handler.threadGroups[i].threadType === 'ITERATION') {
continue;
}
let seriesData = {
name: handler.threadGroups[i].attributes.testname,
data: [],
type: 'line',
step: 'start',
smooth: false,
symbolSize: 5,
showSymbol: false,
lineStyle: {
width: 1
},
itemStyle: {
color: hexToRgb(color[i % color.length]),
borderColor: 'rgba(137,189,2,0.27)',
borderWidth: 12
},
};
let tg = handler.threadGroups[i];
let timePeriod = Math.floor(tg.rampUpTime / tg.step);
let timeInc = timePeriod;
let threadPeriod = Math.floor(tg.threadNumber / tg.step);
let threadInc1 = Math.floor(tg.threadNumber / tg.step);
let threadInc2 = Math.ceil(tg.threadNumber / tg.step);
let inc2count = tg.threadNumber - tg.step * threadInc1;
let times = 1;
switch (tg.unit) {
case 'M':
times *= 60;
break;
case 'H':
times *= 3600;
break;
default:
break;
}
let duration = tg.duration * times;
for (let j = 0; j <= duration; j++) {
// x
let xAxis = handler.options.xAxis.data;
if (xAxis.indexOf(j) < 0) {
xAxis.push(j);
}
if (tg.tgType === 'ThreadGroup') {
seriesData.step = undefined;
if (j === 0) {
seriesData.data.push([0, 0]);
}
if (j >= tg.rampUpTime) {
xAxis.push(duration);
seriesData.data.push([j, tg.threadNumber]);
seriesData.data.push([duration, tg.threadNumber]);
break;
}
} else {
seriesData.step = 'start';
if (j > timePeriod) {
timePeriod += timeInc;
if (inc2count > 0) {
threadPeriod = threadPeriod + threadInc2;
inc2count--;
} else {
threadPeriod = threadPeriod + threadInc1;
}
if (threadPeriod > tg.threadNumber) {
threadPeriod = tg.threadNumber;
//
xAxis.push(duration);
seriesData.data.push([duration, threadPeriod]);
break;
}
}
seriesData.data.push([j, threadPeriod]);
}
}
handler.options.series.push(seriesData);
}
},
getDuration(tg) {
tg.duration = tg.durationHours * 60 * 60 + tg.durationMinutes * 60 + tg.durationSeconds;
return tg.duration;
},
},
watch: {
report: {
handler() {
this.getJmxContent();
},
deep: true
},
planReportTemplate: {
handler() {
if (this.planReportTemplate) {
this.getJmxContent();
}
},
deep: true
}
}
};
</script>
<style scoped>
.pressure-config-container .el-input {
width: 130px;
}
.pressure-config-container .config-form-label {
width: 130px;
}
.pressure-config-container .input-bottom-border input {
border: 0;
border-bottom: 1px solid #DCDFE6;
}
.chart-container {
width: 100%;
height: 300px;
}
.el-col .el-form {
margin-top: 15px;
text-align: left;
}
.el-col {
margin-top: 15px;
text-align: left;
}
.title {
margin-left: 60px;
}
.wordwrap {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@ -0,0 +1,30 @@
<template>
<el-tabs>
<el-tab-pane :label="$t('load_test.pressure_config')">
<performance-pressure-config :is-read-only="true" :test="test" :test-id="testId"/>
</el-tab-pane>
<el-tab-pane :label="$t('load_test.advanced_config')">
<performance-advanced-config :is-read-only="true" :test-id="testId"/>
</el-tab-pane>
</el-tabs>
</template>
<script>
import PerformancePressureConfig from "@/business/components/performance/test/components/PerformancePressureConfig";
import PerformanceAdvancedConfig from "@/business/components/performance/test/components/PerformanceAdvancedConfig";
import PerformanceBasicConfig from "@/business/components/performance/test/components/PerformanceBasicConfig";
export default {
name: "TestConfiguration",
components: {PerformanceBasicConfig, PerformancePressureConfig, PerformanceAdvancedConfig},
props: {
report: Object,
test: Object,
testId: String,
}
};
</script>
<style scoped>
</style>

View File

@ -3,13 +3,13 @@
<!-- 基本配置 -->
<el-row>
<el-col :span="6">
<el-form :inline="true">
<el-form :inline="true" :disabled="isReadOnly">
<el-form-item>
<div>{{ $t('load_test.connect_timeout') }}</div>
</el-form-item>
<el-form-item>
<el-input-number
:disabled="readOnly" size="mini" v-model="timeout"
size="mini" v-model="timeout"
controls-position="right"
:min="0"/>
</el-form-item>
@ -19,13 +19,13 @@
</el-form>
</el-col>
<el-col :span="6">
<el-form :inline="true">
<el-form :inline="true" :disabled="isReadOnly">
<el-form-item>
<div>{{ $t('load_test.response_timeout') }}</div>
</el-form-item>
<el-form-item>
<el-input-number
:disabled="readOnly" size="mini" :min="0"
size="mini" :min="0"
controls-position="right"
v-model="responseTimeout"/>
</el-form-item>
@ -35,7 +35,7 @@
</el-form>
</el-col>
<el-col :span="6">
<el-form :inline="true">
<el-form :inline="true" :disabled="isReadOnly">
<el-form-item>
<div>
{{ $t('load_test.granularity') }}
@ -65,13 +65,13 @@
</el-form>
</el-col>
<el-col :span="6">
<el-form :inline="true">
<el-form :inline="true" :disabled="isReadOnly">
<el-form-item>
<div>{{ $t('load_test.custom_http_code') }}</div>
</el-form-item>
<el-form-item>
<el-input
:disabled="readOnly" size="mini" v-model="statusCodeStr"
size="mini" v-model="statusCodeStr"
:placeholder="$t('load_test.separated_by_commas')"
@input="checkStatusCode"></el-input>
</el-form-item>
@ -83,7 +83,9 @@
<el-row type="flex" justify="start">
<el-col :span="8">
<h3>{{ $t('load_test.domain_bind') }}</h3>
<el-button :disabled="readOnly" icon="el-icon-circle-plus-outline" plain size="mini" @click="add('domains')">
<el-button icon="el-icon-circle-plus-outline"
:disabled="isReadOnly"
plain size="mini" @click="add('domains')">
{{ $t('commons.add') }}
</el-button>
</el-col>
@ -98,7 +100,7 @@
<template v-slot:default="{row}">
<el-input
size="mini"
v-if="!readOnly"
v-if="!isReadOnly"
type="textarea"
:rows="1"
class="edit-input"
@ -116,7 +118,7 @@
<template v-slot:default="{row}">
<el-input
size="mini"
v-if="!readOnly"
v-if="!isReadOnly"
type="textarea"
class="edit-input"
:rows="1"
@ -132,7 +134,7 @@
show-overflow-tooltip>
<template v-slot:default="{row}">
<el-switch
:disabled="readOnly"
:disabled="isReadOnly"
size="mini"
v-model="row.enable"
inactive-color="#DCDFE6"
@ -142,8 +144,8 @@
</el-table-column>
<el-table-column align="center" :label="$t('load_test.operating')">
<template v-slot:default="{row, $index}">
<ms-table-operator-button :disabled="readOnly" :tip="$t('commons.delete')" icon="el-icon-delete"
type="danger"
<ms-table-operator-button :tip="$t('commons.delete')" icon="el-icon-delete"
type="danger" :disabled="isReadOnly"
@exec="del(row, 'domains', $index)"/>
</template>
</el-table-column>
@ -167,12 +169,12 @@
</el-table-column>
<el-table-column align="center" prop="csvSplit" :label="$t('load_test.csv_split')">
<template v-slot:default="{row}">
<el-switch :disabled="readOnly" v-model="row.csvSplit"/>
<el-switch :disabled="isReadOnly" v-model="row.csvSplit"/>
</template>
</el-table-column>
<el-table-column align="center" prop="csvHasHeader" :label="$t('load_test.csv_has_header')">
<template v-slot:default="{row}">
<el-switch :disabled="readOnly || !row.csvSplit" v-model="row.csvHasHeader"/>
<el-switch :disabled="isReadOnly || !row.csvSplit" v-model="row.csvHasHeader"/>
</template>
</el-table-column>
</el-table>
@ -183,7 +185,9 @@
<el-row>
<el-col :span="8">
<h3>{{ $t('load_test.params') }}</h3>
<el-button :disabled="readOnly" icon="el-icon-circle-plus-outline" plain size="mini" @click="add('params')">
<el-button icon="el-icon-circle-plus-outline"
:disabled="isReadOnly"
plain size="mini" @click="add('params')">
{{ $t('commons.add') }}
</el-button>
</el-col>
@ -198,7 +202,7 @@
<template v-slot:default="{row}">
<el-input
size="mini"
v-if="!readOnly"
v-if="!isReadOnly"
type="textarea"
:rows="1"
class="edit-input"
@ -213,13 +217,9 @@
:label="$t('load_test.param_value')"
show-overflow-tooltip align="center">
<template v-slot:default="{row}">
<!-- <template v-if="row.edit">
<el-input v-model="row.value" class="edit-input" size="mini"/>
</template>
<span v-else>{{ row.value }}</span>-->
<el-input
size="mini"
v-if="!readOnly"
v-if="!isReadOnly"
type="textarea"
class="edit-input"
:rows="1"
@ -235,7 +235,7 @@
show-overflow-tooltip>
<template v-slot:default="{row}">
<el-switch
:disabled="readOnly"
:disabled="isReadOnly"
size="mini"
v-model="row.enable"
inactive-color="#DCDFE6">
@ -244,8 +244,9 @@
</el-table-column>
<el-table-column align="center" :label="$t('load_test.operating')">
<template v-slot:default="{row, $index}">
<ms-table-operator-button :disabled="readOnly" :tip="$t('commons.delete')" icon="el-icon-delete"
<ms-table-operator-button :tip="$t('commons.delete')" icon="el-icon-delete"
type="danger"
:disabled="isReadOnly"
@exec="del(row, 'params', $index)"/>
</template>
</el-table-column>
@ -257,7 +258,9 @@
<el-row>
<el-col :span="8">
<h3>JMeter Properties</h3>
<el-button :disabled="readOnly" icon="el-icon-circle-plus-outline" plain size="mini" @click="add('properties')">
<el-button icon="el-icon-circle-plus-outline"
:disabled="isReadOnly"
plain size="mini" @click="add('properties')">
{{ $t('commons.add') }}
</el-button>
</el-col>
@ -272,7 +275,7 @@
<template v-slot:default="{row}">
<el-input
size="mini"
v-if="!readOnly"
v-if="!isReadOnly"
type="textarea"
:rows="1"
class="edit-input"
@ -287,13 +290,9 @@
:label="$t('load_test.param_value')"
show-overflow-tooltip align="center">
<template v-slot:default="{row}">
<!-- <template v-if="row.edit">
<el-input v-model="row.value" class="edit-input" size="mini"/>
</template>
<span v-else>{{ row.value }}</span>-->
<el-input
size="mini"
v-if="!readOnly"
v-if="!isReadOnly"
type="textarea"
class="edit-input"
:rows="1"
@ -309,7 +308,7 @@
show-overflow-tooltip>
<template v-slot:default="{row}">
<el-switch
:disabled="readOnly"
:disabled="isReadOnly"
size="mini"
v-model="row.enable"
inactive-color="#DCDFE6">
@ -318,8 +317,9 @@
</el-table-column>
<el-table-column align="center" :label="$t('load_test.operating')">
<template v-slot:default="{row, $index}">
<ms-table-operator-button :disabled="readOnly" :tip="$t('commons.delete')" icon="el-icon-delete"
<ms-table-operator-button :tip="$t('commons.delete')" icon="el-icon-delete"
type="danger"
:disabled="isReadOnly"
@exec="del(row, 'properties', $index)"/>
</template>
</el-table-column>
@ -331,10 +331,12 @@
<el-row>
<el-col :span="8">
<h3>{{ $t('commons.monitor') }}</h3>
<el-button :disabled="readOnly" icon="el-icon-circle-plus-outline" plain size="mini" @click="addMonitor">
<el-button icon="el-icon-circle-plus-outline" :disabled="isReadOnly"
plain size="mini" @click="addMonitor">
{{ $t('commons.add') }}
</el-button>
<el-button :disabled="readOnly" icon="el-icon-circle-plus-outline" plain size="mini"
<el-button icon="el-icon-circle-plus-outline" plain size="mini"
:disabled="isReadOnly"
@click="batchAddMonitor">
{{ $t('commons.batch_add') }}
</el-button>
@ -348,20 +350,6 @@
prop="name"
:label="$t('commons.name')">
</el-table-column>
<!-- <el-table-column-->
<!-- align="center"-->
<!-- prop="environmentName"-->
<!-- label="所属环境">-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- align="center"-->
<!-- prop="authStatus"-->
<!-- label="认证状态">-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- align="center"-->
<!-- prop="monitorStatus"-->
<!-- label="监控状态">-->
<el-table-column
align="center"
prop="ip"
@ -379,10 +367,12 @@
</el-table-column>
<el-table-column align="center" :label="$t('load_test.operating')">
<template v-slot:default="{row, $index}">
<ms-table-operator-button :disabled="readOnly" tip="编辑" icon="el-icon-edit"
<ms-table-operator-button tip="编辑" icon="el-icon-edit"
type="primary"
:disabled="isReadOnly"
@exec="modifyMonitor(row, $index)"/>
<ms-table-operator-button :disabled="readOnly" :tip="$t('commons.delete')" icon="el-icon-delete"
<ms-table-operator-button :tip="$t('commons.delete')" icon="el-icon-delete"
:disabled="isReadOnly"
type="danger"
@exec="delMonitor(row, $index)"/>
</template>
@ -399,7 +389,6 @@
<script>
import MsTableOperatorButton from "@/business/components/common/components/MsTableOperatorButton.vue";
import EditMonitor from "@/business/components/performance/test/components/EditMonitor";
import {hasPermission} from "@/common/js/utils";
import BatchAddMonitor from "@/business/components/performance/test/components/BatchAddMonitor";
export default {
@ -429,17 +418,21 @@ export default {
{start: 60001, end: 180000, granularity: 1800},
{start: 180001, end: 360000, granularity: 3600},
],
readOnly: false,
};
},
props: {
testId: String,
isReadOnly: {
type: Boolean,
default() {
return false;
}
}
},
mounted() {
if (this.testId) {
this.getAdvancedConfig();
}
this.readOnly = !hasPermission('PROJECT_PERFORMANCE_TEST:READ+EDIT');
},
watch: {
testId() {

View File

@ -2,15 +2,15 @@
<div v-loading="result.loading" class="pressure-config-container">
<el-row>
<el-col>
<el-form :inline="true">
<el-form :inline="true" :disabled="isReadOnly">
<el-form-item :label="$t('load_test.select_resource_pool')">
<el-select v-model="resourcePool" :disabled="isReadOnly" size="mini" @change="resourcePoolChange">
<el-select v-model="resourcePool" size="mini" @change="resourcePoolChange">
<el-option
v-for="item in resourcePools"
:key="item.id"
:label="item.name"
:disabled="!item.performance"
:value="item.id">
v-for="item in resourcePools"
:key="item.id"
:label="item.name"
:disabled="!item.performance"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
@ -22,7 +22,6 @@
</el-form-item>
<el-form-item v-if="autoStop" :label="$t('load_test.reaches_duration')">
<el-input-number controls-position="right"
:disabled="isReadOnly"
v-model="autoStopDelay"
:min="1"
:max="9999"
@ -67,10 +66,10 @@
</el-col>
</el-row>
</template>
<el-form :inline="true" label-width="100px">
<el-form :inline="true" label-width="100px" :disabled="isReadOnly">
<el-form-item :label="$t('load_test.thread_num')">
<el-input-number controls-position="right"
:disabled="isReadOnly"
v-model="threadGroup.threadNumber"
@change="calculateTotalChart()"
:min="1"
@ -79,18 +78,20 @@
</el-form-item>
<br>
<el-form-item :label="$t('load_test.on_sample_error')">
<el-select v-model="threadGroup.onSampleError" :disabled="isReadOnly" size="mini">
<el-select v-model="threadGroup.onSampleError" size="mini">
<el-option
v-for="item in onSampleErrors"
:key="item.value"
:label="item.label"
:value="item.value">
v-for="item in onSampleErrors"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<br>
<el-form-item :label="$t('load_test.run_mode')">
<el-radio-group v-model="threadGroup.threadType" @change="calculateTotalChart()" size="mini">
<el-radio-group v-model="threadGroup.threadType"
@change="calculateTotalChart()"
size="mini">
<el-radio-button label="DURATION">{{ $t('load_test.by_duration') }}</el-radio-button>
<el-radio-button label="ITERATION">{{ $t('load_test.by_iteration') }}</el-radio-button>
</el-radio-group>
@ -98,7 +99,7 @@
<div v-if="threadGroup.threadType === 'DURATION'">
<el-form-item :label="$t('load_test.duration')">
<el-input-number controls-position="right"
:disabled="isReadOnly"
v-model="threadGroup.durationHours"
:min="0"
:max="9999"
@ -108,7 +109,7 @@
<el-form-item :label="$t('schedule.cron.hours')" label-width="40px"/>
<el-form-item>
<el-input-number controls-position="right"
:disabled="isReadOnly"
v-model="threadGroup.durationMinutes"
:min="0"
:max="59"
@ -118,7 +119,7 @@
<el-form-item :label="$t('schedule.cron.minutes')" label-width="40px"/>
<el-form-item>
<el-input-number controls-position="right"
:disabled="isReadOnly"
v-model="threadGroup.durationSeconds"
:min="0"
:max="59"
@ -142,7 +143,7 @@
<div v-if="threadGroup.tgType === 'com.blazemeter.jmeter.threads.concurrency.ConcurrencyThreadGroup'">
<el-form-item label="Ramp-Up">
<el-input-number controls-position="right"
:disabled="isReadOnly"
:min="1"
v-if="rampUpTimeVisible"
:max="getDuration(threadGroup)"
@ -152,7 +153,7 @@
</el-form-item>
<el-form-item label="Step" label-width="50px">
<el-input-number controls-position="right"
:disabled="isReadOnly"
:min="1"
:max="Math.min(threadGroup.threadNumber, threadGroup.rampUpTime)"
v-model="threadGroup.step"
@ -164,7 +165,7 @@
<div v-if="threadGroup.tgType === 'ThreadGroup'">
<el-form-item label="Ramp-Up">
<el-input-number controls-position="right"
:disabled="isReadOnly"
v-if="rampUpTimeVisible"
:min="1"
:max="getDuration(threadGroup)"
@ -178,7 +179,7 @@
<div v-if="threadGroup.threadType === 'ITERATION'">
<el-form-item :label="$t('load_test.iterate_num')">
<el-input-number controls-position="right"
:disabled="isReadOnly"
v-model="threadGroup.iterateNum"
:min="1"
:max="9999999"
@ -200,7 +201,7 @@
<br>
<el-form-item label="Ramp-Up">
<el-input-number controls-position="right"
:disabled="isReadOnly"
:min="1"
v-model="threadGroup.iterateRampUp"
size="mini"/>
@ -209,7 +210,7 @@
<!-- 资源池自己配置各个节点的并发 -->
<div v-if="resourcePoolType === 'NODE'">
<el-form-item :label="$t('load_test.resource_strategy')">
<el-radio-group v-model="threadGroup.strategy" :disabled="isReadOnly" size="mini">
<el-radio-group v-model="threadGroup.strategy" size="mini">
<el-radio-button label="auto">{{ $t('load_test.auto_ratio') }}</el-radio-button>
<el-radio-button label="specify">{{ $t('load_test.specify_resource') }}</el-radio-button>
<el-radio-button label="custom">{{ $t('load_test.custom_ratio') }}</el-radio-button>
@ -218,12 +219,12 @@
<div v-if="threadGroup.strategy === 'auto'"></div>
<div v-else-if="threadGroup.strategy === 'specify'">
<el-form-item :label="$t('load_test.specify_resource')">
<el-select v-model="threadGroup.resourceNodeIndex" :disabled="isReadOnly" size="mini">
<el-select v-model="threadGroup.resourceNodeIndex" size="mini">
<el-option
v-for="(node, index) in resourceNodes"
:key="node.ip"
:label="node.ip"
:value="index">
v-for="(node, index) in resourceNodes"
:key="node.ip"
:label="node.ip"
:value="index">
</el-option>
</el-select>
</el-form-item>
@ -235,7 +236,9 @@
<el-table-column prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"/>
<el-table-column prop="ratio" :label="$t('test_track.home.percentage')">
<template v-slot:default="{row}">
<el-input-number size="mini" v-model="row.ratio" :min="0" :step=".1" controls-position="right"
<el-input-number size="mini" v-model="row.ratio"
:min="0" :step=".1" controls-position="right"
:max="1"></el-input-number>
</template>
</el-table-column>
@ -257,7 +260,6 @@
<script>
import MsChart from "@/business/components/common/chart/MsChart";
import {findThreadGroup} from "@/business/components/performance/test/model/ThreadGroup";
import {hasPermission} from "@/common/js/utils";
const HANDLER = "handler";
const THREAD_GROUP_TYPE = "tgType";
@ -287,7 +289,7 @@ const RATIOS = "ratios";
const hexToRgb = function (hex) {
return 'rgb(' + parseInt('0x' + hex.slice(1, 3)) + ',' + parseInt('0x' + hex.slice(3, 5))
+ ',' + parseInt('0x' + hex.slice(5, 7)) + ')';
+ ',' + parseInt('0x' + hex.slice(5, 7)) + ')';
};
export default {
@ -299,6 +301,12 @@ export default {
},
testId: {
type: String
},
isReadOnly: {
type: Boolean,
default() {
return false;
}
}
},
data() {
@ -321,7 +329,6 @@ export default {
serializeThreadGroups: false,
autoStop: false,
autoStopDelay: 30,
isReadOnly: false,
rampUpTimeVisible: true,
};
},
@ -344,13 +351,15 @@ export default {
}
this.resourcePool = this.test.testResourcePoolId;
this.getResourcePools();
this.isReadOnly = !hasPermission('PROJECT_PERFORMANCE_TEST:READ+EDIT');
},
watch: {
test(n) {
if (n.testResourcePoolId) {
this.resourcePool = n.testResourcePoolId;
}
test: {
handler(n) {
if (n.testResourcePoolId) {
this.resourcePool = n.testResourcePoolId;
}
},
deep: true,
},
testId() {
if (this.testId) {
@ -570,8 +579,8 @@ export default {
let tg = handler.threadGroups[i];
if (tg.enabled === 'false' ||
tg.deleted === 'true' ||
tg.threadType === 'ITERATION') {
tg.deleted === 'true' ||
tg.threadType === 'ITERATION') {
continue;
}
if (this.getDuration(tg) < tg.rampUpTime) {
@ -686,7 +695,7 @@ export default {
}
if (!tg.threadNumber || !tg.duration
|| !tg.rampUpTime || !tg.step || !tg.iterateNum) {
|| !tg.rampUpTime || !tg.step || !tg.iterateNum) {
this.$warning(this.$t('load_test.pressure_config_params_is_empty'));
this.$emit('changeActive', '1');
return false;

View File

@ -48,10 +48,6 @@
<el-divider/>
<div ref="resume">
<el-tabs v-model="active">
<el-tab-pane :label="$t('load_test.pressure_config')">
<ms-performance-pressure-config :is-share="isShare" :plan-report-template="planReportTemplate"
:share-id="shareId" :is-read-only="true" :report="report"/>
</el-tab-pane>
<el-tab-pane :label="$t('report.test_overview')">
<ms-report-test-overview :report="report" :is-share="isShare" :plan-report-template="planReportTemplate"
:share-id="shareId" ref="testOverview"/>
@ -77,6 +73,9 @@
<monitor-card :report="report" :is-share="isShare" :plan-report-template="planReportTemplate"
:share-id="shareId"/>
</el-tab-pane>
<el-tab-pane :label="$t('测试配置')">
<ms-test-configuration :report="report" :test="test" :test-id="testId"/>
</el-tab-pane>
</el-tabs>
</div>
@ -112,7 +111,6 @@ import MsReportRequestStatistics from "@/business/components/performance/report/
import MsReportTestOverview from "@/business/components/performance/report/components/TestOverview";
import MsContainer from "@/business/components/common/components/MsContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
import MsPerformancePressureConfig from "@/business/components/performance/report/components/PerformancePressureConfig";
import MonitorCard from "@/business/components/performance/report/components/MonitorCard";
import MsReportTestDetails from '@/business/components/performance/report/components/TestDetails';
import {
@ -121,11 +119,13 @@ import {
getSharePerformanceReport,
getSharePerformanceReportTime
} from "@/network/load-test";
import MsTestConfiguration from "@/business/components/performance/report/components/TestConfiguration";
export default {
name: "LoadCaseReportView",
components: {
MsTestConfiguration,
MonitorCard,
MsPerformanceReportExport,
MsReportErrorLog,
@ -135,12 +135,11 @@ export default {
MsReportTestDetails,
MsContainer,
MsMainContainer,
MsPerformancePressureConfig
},
data() {
return {
result: {},
active: '1',
active: '0',
status: '',
reportName: '',
testId: '',
@ -158,6 +157,7 @@ export default {
reportExportVisible: false,
testPlan: {testResourcePoolId: null},
show: true,
test: {testResourcePoolId: null},
};
},
props: {
@ -393,6 +393,7 @@ export default {
if (data) {
this.status = data.status;
this.$set(this, "report", data);
this.$set(this.test, "testResourcePoolId", data.testResourcePoolId);
this.checkReportStatus(data.status);
if (this.status === "Completed" || this.status === "Running") {
this.initReportTimeInfo();