重构性能测试和功能测试页面

This commit is contained in:
chenjianxing 2020-03-12 10:44:15 +08:00
parent 90109ade6a
commit c3ed99f330
28 changed files with 1051 additions and 344 deletions

View File

@ -105,6 +105,7 @@ export default {
'basic_config': 'Scene Configuration',
'pressure_config': 'Pressure configuration',
'advanced_config': 'Advanced Configuration',
'runtime_config': 'Runtime Configuration',
'is_running': 'Test is running! ',
'test_name_is_null': 'Test name cannot be empty! ',
'project_is_null': 'Project cannot be empty! ',

View File

@ -106,6 +106,7 @@ export default {
'basic_config': '场景配置',
'pressure_config': '压力配置',
'advanced_config': '高级配置',
'runtime_config': '运行配置',
'is_running': '正在运行!',
'test_name_is_null': '测试名称不能为空!',
'project_is_null': '项目不能为空!',

View File

@ -11,27 +11,12 @@
<ms-user/>
</el-col>
</el-row>
<el-row id="header-bottom" type="flex" justify="space-between" align="middle">
<el-col :span="10">
<ms-menus/>
</el-col>
<el-col :span="4">
<el-row type="flex" justify="center" align="middle">
<router-link to="/createTest" v-permission="['test_user','test_manager']">
<el-button type="primary" size="small">{{$t('load_test.create')}}</el-button>
</router-link>
</el-row>
</el-col>
<el-col :span="10">
</el-col>
</el-row>
<ms-view/>
<ms-web-socket/>
</el-col>
</template>
<script>
import MsMenus from "./components/HeaderMenus";
import MsTopMenus from "./components/HeaderTopMenus";
import MsView from "./components/router/View";
import MsUser from "./components/HeaderUser";
@ -57,7 +42,7 @@
window.location.href = "/login"
});
},
components: {MsWebSocket, MsUser, MsMenus, MsView, MsTopMenus},
components: {MsWebSocket, MsUser, MsView, MsTopMenus},
methods: {}
}
</script>
@ -91,14 +76,6 @@
background-image: url("../assets/MeterSphere-反白.png");
}
#header-bottom {
height: 40px;
padding: 0 15px;
border-bottom: 1px solid #E6E6E6;
cursor: default;
color: #404040;
}
.menus > * {
color: inherit;
padding: 0;

View File

@ -1,76 +1,99 @@
<template>
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router
:default-active='$route.path'>
<el-menu-item index="/setting/personsetting">
{{ $t("i18n.home") }}
</el-menu-item>
<el-submenu index="3" popper-class="submenu" v-permission="['test_manager']">
<template slot="title">{{$t('commons.project')}}</template>
<ms-recent-project/>
<el-divider/>
<el-menu-item index="/project/all">
<font-awesome-icon :icon="['fa', 'list-ul']"/>
<span style="padding-left: 5px;">{{$t('commons.show_all')}}</span>
<div id="menu-bar">
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router
:default-active='$route.path'>
<el-menu-item :index="'/' + beaseUrl + '/home'">
{{ $t("i18n.home") }}
</el-menu-item>
<el-menu-item index="/project/create">
<el-button type="text">{{$t('project.create')}}</el-button>
</el-menu-item>
</el-submenu>
<el-submenu index="4" popper-class="submenu" v-permission="['test_manager', 'test_user']">
<template slot="title">{{$t('commons.test')}}</template>
<ms-recent-test-plan/>
<el-divider/>
<el-menu-item index="/loadtest/all">
<font-awesome-icon :icon="['fa', 'list-ul']"/>
<span style="padding-left: 5px;">{{$t('commons.show_all')}}</span>
</el-menu-item>
<el-menu-item index="/createTest">
<el-button type="text">{{$t('load_test.create')}}</el-button>
</el-menu-item>
</el-submenu>
<el-submenu index="5" popper-class="submenu" v-permission="['test_manager', 'test_user', 'test_viewer']">
<template slot="title">{{$t('commons.report')}}</template>
<ms-recent-report/>
<el-divider/>
<el-menu-item index="/report/all">
<font-awesome-icon :icon="['fa', 'list-ul']"/>
<span style="padding-left: 5px;">{{$t('commons.show_all')}}</span>
</el-menu-item>
</el-submenu>
</el-menu>
<el-submenu index="3" popper-class="submenu" v-permission="['test_manager']">
<template slot="title">{{$t('commons.project')}}</template>
<ms-recent-project/>
<el-divider/>
<el-menu-item :index="'/' + beaseUrl + '/project/all'">
<font-awesome-icon :icon="['fa', 'list-ul']"/>
<span style="padding-left: 5px;">{{$t('commons.show_all')}}</span>
</el-menu-item>
<el-menu-item :index="'/' + beaseUrl + '/project/create'">
<el-button type="text">{{$t('project.create')}}</el-button>
</el-menu-item>
</el-submenu>
<el-submenu index="4" popper-class="submenu" v-permission="['test_manager', 'test_user']">
<template slot="title">{{$t('commons.test')}}</template>
<performance-recent-test-plan v-if="beaseUrl == 'performance'"/>
<functional-recent-test-plan v-if="beaseUrl == 'functional'"/>
<el-divider/>
<el-menu-item :index="'/' + beaseUrl + '/plan/all'">
<font-awesome-icon :icon="['fa', 'list-ul']"/>
<span style="padding-left: 5px;">{{$t('commons.show_all')}}</span>
</el-menu-item>
<el-menu-item :index="'/' + beaseUrl + '/plan/create'">
<el-button type="text">{{$t('load_test.create')}}</el-button>
</el-menu-item>
</el-submenu>
<el-submenu index="5" popper-class="submenu" v-permission="['test_manager', 'test_user', 'test_viewer']">
<template slot="title">{{$t('commons.report')}}</template>
<performance-recent-report v-if="beaseUrl == 'performance'"/>
<functional-recent-report v-if="beaseUrl == 'functional'"/>
<el-divider/>
<el-menu-item :index="'/' + beaseUrl + '/report/all'">
<font-awesome-icon :icon="['fa', 'list-ul']"/>
<span style="padding-left: 5px;">{{$t('commons.show_all')}}</span>
</el-menu-item>
</el-submenu>
<router-link class="header-bottom" :to="'/' + beaseUrl + '/plan/create'" v-permission="['test_user','test_manager']">
<el-button type="primary" size="small">{{$t('load_test.create')}}</el-button>
</router-link>
</el-menu>
</div>
</template>
<script>
import MsRecentTestPlan from "./testPlan/RecentTestPlan";
import PerformanceRecentTestPlan from "./testPlan/PerformanceRecentTestPlan";
import FunctionalRecentTestPlan from "./testPlan/FunctionalRecentTestPlan";
import MsRecentProject from "./project/RecentProject";
import MsRecentReport from "./report/RecentReport";
import PerformanceRecentReport from "./report/PerformanceRecentReport";
import FunctionalRecentReport from "./report/FunctionalRecentReport";
export default {
name: "MsMenus",
components: {MsRecentReport, MsRecentTestPlan, MsRecentProject}
components: {PerformanceRecentReport, PerformanceRecentTestPlan, MsRecentProject, FunctionalRecentTestPlan, FunctionalRecentReport},
props: {
beaseUrl: {
type: String
}
}
}
</script>
<style>
.header-menu.el-menu--horizontal > li.el-menu-item {
padding-left: 0;
}
.header-menu.el-menu--horizontal > li {
height: 39px;
line-height: 40px;
color: inherit;
color: dimgray;
}
.header-menu.el-menu--horizontal > li.el-submenu > * {
height: 39px;
line-height: 40px;
color: inherit;
color: dimgray;
}
.header-bottom {
line-height: 40px;
margin-left: 20%;
}
</style>
<style scoped>
.el-divider--horizontal {
margin: 0;
}
#menu-bar {
border-bottom: 1px solid #E6E6E6;
}
</style>

View File

@ -7,10 +7,10 @@
:default-active="activeIndex"
@select="handleSelect"
router>
<el-menu-item index="1" v-permission="['test_manager','test_user','test_viewer']">
<el-menu-item index="/functional" v-permission="['test_manager','test_user','test_viewer']">
功能测试
</el-menu-item>
<el-menu-item index="/loadtest" onselectstart="return false"
<el-menu-item index="/performance" onselectstart="return false"
v-permission="['test_manager','test_user','test_viewer']">
性能测试
</el-menu-item>

View File

@ -1,196 +0,0 @@
<template>
<chart :options="bar"></chart>
</template>
<script>
import echarts from 'echarts'
export default {
name: "MsChart",
data() {
return {
bar: {
backgroundColor: '#394056',
title: {
top: 20,
text: 'Requests',
textStyle: {
fontWeight: 'normal',
fontSize: 16,
color: '#F1F1F3'
},
left: '1%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
color: '#57617B'
}
}
},
legend: {
top: 20,
icon: 'rect',
itemWidth: 14,
itemHeight: 5,
itemGap: 13,
data: ['CMCC', 'CTCC', 'CUCC'],
right: '4%',
textStyle: {
fontSize: 12,
color: '#F1F1F3'
}
},
grid: {
top: 100,
left: '2%',
right: '2%',
bottom: '2%',
containLabel: true
},
xAxis: [{
type: 'category',
boundaryGap: false,
axisLine: {
lineStyle: {
color: '#57617B'
}
},
data: ['13:00', '13:05', '13:10', '13:15', '13:20', '13:25', '13:30', '13:35', '13:40', '13:45', '13:50', '13:55']
}],
yAxis: [{
type: 'value',
name: '(%)',
axisTick: {
show: false
},
axisLine: {
lineStyle: {
color: '#57617B'
}
},
axisLabel: {
margin: 10,
textStyle: {
fontSize: 14
}
},
splitLine: {
lineStyle: {
color: '#57617B'
}
}
}],
series: [{
name: 'CMCC',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(137, 189, 27, 0.3)'
}, {
offset: 0.8,
color: 'rgba(137, 189, 27, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(137,189,27)',
borderColor: 'rgba(137,189,2,0.27)',
borderWidth: 12
}
},
data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122]
}, {
name: 'CTCC',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(0, 136, 212, 0.3)'
}, {
offset: 0.8,
color: 'rgba(0, 136, 212, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(0,136,212)',
borderColor: 'rgba(0,136,212,0.2)',
borderWidth: 12
}
},
data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150]
}, {
name: 'CUCC',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(219, 50, 51, 0.3)'
}, {
offset: 0.8,
color: 'rgba(219, 50, 51, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(219,50,51)',
borderColor: 'rgba(219,50,51,0.2)',
borderWidth: 12
}
},
data: [220, 182, 125, 145, 122, 191, 134, 150, 120, 110, 165, 122]
}]
},
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,17 @@
<template>
<div>
功能测试图表
</div>
</template>
<script>
export default {
name: "PerformanceChart"
}
</script>
<style scoped>
</style>

View File

@ -15,7 +15,7 @@
import {ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "../../../common/constants";
export default {
name: "MsRecentReport",
name: "PerformanceRecentReport",
mounted() {
const rolesString = localStorage.getItem("roles");
const roles = rolesString.split(',');

View File

@ -81,7 +81,7 @@
<script>
export default {
name: "MsAllTestReport",
name: "FunctionalTestReport",
created: function () {
this.initTableData();
},

View File

@ -0,0 +1,43 @@
<template>
<el-menu router menu-trigger="click" :default-active="$route.path">
<div class="recent-text">
<i class="el-icon-time"/>
{{$t('load_test.recent')}}
</div>
<el-menu-item :key="p.id" v-for="p in recentReports"
:index="'/report/' + p.id" :route="{name:'report', params:{projectId:p.id, projectName:p.name}}">
{{ p.name }}
</el-menu-item>
</el-menu>
</template>
<script>
import {ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "../../../common/constants";
export default {
name: "PerformanceRecentReport",
mounted() {
const rolesString = localStorage.getItem("roles");
const roles = rolesString.split(',');
if (roles.indexOf(ROLE_TEST_MANAGER) > -1 || roles.indexOf(ROLE_TEST_USER) > -1 || roles.indexOf(ROLE_TEST_VIEWER) > -1) {
this.$get('/report/recent/5', (response) => {
this.recentReports = response.data;
});
}
},
methods: {},
data() {
return {
recentReports: [],
}
}
}
</script>
<style scoped>
.recent-text {
padding-left: 10%;
color: #777777;
}
</style>

View File

@ -0,0 +1,183 @@
<template>
<div class="testreport-container" v-loading="result.loading">
<div class="main-content">
<el-card>
<div slot="header">
<el-row type="flex" justify="space-between" align="middle">
<span class="title">{{$t('commons.report')}}</span>
<span class="search">
<el-input type="text" size="small" :placeholder="$t('report.search_by_name')"
prefix-icon="el-icon-search"
maxlength="60"
v-model="condition" @change="search" clearable/>
</span>
</el-row>
</div>
<el-table :data="tableData" class="test-content">
<el-table-column
prop="name"
:label="$t('commons.name')"
width="150"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="description"
:label="$t('commons.description')"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="testName"
:label="$t('report.test_name')"
width="150"
show-overflow-tooltip>
</el-table-column>
<el-table-column
width="250"
:label="$t('commons.create_time')">
<template slot-scope="scope">
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
width="250"
:label="$t('commons.update_time')">
<template slot-scope="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
width="150"
:label="$t('commons.operating')">
<template slot-scope="scope">
<el-button @click="handleEdit(scope.row)" type="primary" icon="el-icon-edit" size="mini" circle/>
<el-button @click="handleDelete(scope.row)" type="danger" icon="el-icon-delete" size="mini" circle/>
</template>
</el-table-column>
</el-table>
<div>
<el-row>
<el-col :span="22" :offset="1">
<div class="table-page">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="currentPage"
:page-sizes="[5, 10, 20, 50, 100]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</el-col>
</el-row>
</div>
</el-card>
</div>
</div>
</template>
<script>
export default {
name: "PerformanceTestReport",
created: function () {
this.initTableData();
},
data() {
return {
result: {},
queryPath: "/report/list/all",
deletePath: "/report/delete/",
condition: "",
projectId: null,
tableData: [],
multipleSelection: [],
currentPage: 1,
pageSize: 5,
total: 0,
loading: false,
testId: null,
}
},
methods: {
initTableData() {
let param = {
name: this.condition,
};
this.result = this.$post(this.buildPagePath(this.queryPath), param, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
});
},
search() {
this.initTableData();
},
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
},
handleSizeChange(size) {
this.pageSize = size;
this.initTableData();
},
handleCurrentChange(current) {
this.currentPage = current;
this.initTableData();
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleEdit() {
},
handleDelete(report) {
this.$alert(this.$t('load_test.delete_confirm') + report.name + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this._handleDelete(report);
}
}
});
},
_handleDelete(report) {
this.result = this.$post(this.deletePath + report.id, {},() => {
this.$message({
message: this.$t('commons.delete_success'),
type: 'success'
});
this.initTableData();
});
},
}
}
</script>
<style scoped>
.testreport-container {
padding: 15px;
width: 100%;
height: 100%;
box-sizing: border-box;
}
.main-content {
margin: 0 auto;
width: 100%;
max-width: 1200px;
}
.test-content {
width: 100%;
}
.table-page {
padding-top: 20px;
margin-right: -9px;
float: right;
}
</style>

View File

@ -14,7 +14,7 @@
<style scoped>
#body {
width: 100%;
height: calc(100vh - 80px);
height: calc(100vh - 40px);
background-color: #F5F5F5;
}

View File

@ -3,8 +3,8 @@ import VueRouter from 'vue-router'
import RouterSidebar from "./RouterSidebar";
import Setting from "../settings/Setting";
import User from "../settings/system/User";
import EditTestPlan from "../testPlan/EditTestPlan";
import AllTestPlan from "../testPlan/AllTestPlan";
import EditPerformanceTestPlan from "../testPlan/EditPerformanceTestPlan";
import PerformanceTestPlan from "../testPlan/PerformanceTestPlan";
import Organization from "../settings/system/Organization";
import OrganizationMember from "../settings/organization/OrganizationMember";
import Member from "../settings/workspace/WorkspaceMember";
@ -13,8 +13,15 @@ import MsProject from "../project/MsProject";
import OrganizationWorkspace from "../settings/organization/OrganizationWorkspace";
import PersonSetting from "../settings/personal/PersonSetting";
import SystemWorkspace from "../settings/system/SystemWorkspace";
import MsChart from "../project/MsChart";
import AllTestReport from "../report/AllTestReport";
import PerformanceChart from "../project/PerformanceChart";
import PerformanceTestReport from "../report/PerformanceTestReport";
import FunctionalTestReport from "../report/FunctionalTestReport";
import FunctionalTest from "../testPlan/FunctionalTest";
import PerformanceTest from "../testPlan/PerformanceTest";
import EditFunctionalTestPlan from "../testPlan/EditFunctionalTestPlan";
import PerformanceTestHome from "../testPlan/PerformanceTestHome";
import FunctionalTestPlan from "../testPlan/FunctionalTestPlan";
import FunctionalTestHome from "../testPlan/FunctionalTestHome";
Vue.use(VueRouter);
@ -68,53 +75,92 @@ const router = new VueRouter({
]
},
{
path: "/createTest",
name: "createTest",
path: "/functional",
name: "functional",
redirect: "/functional/home",
components: {
content: EditTestPlan
}
},
{
path: "/editTest/:testId",
name: "editTest",
components: {
content: EditTestPlan
content: FunctionalTest
},
props: {
content: (route) => {
return {
...route.params
children: [
{
path: 'home',
component: FunctionalTestHome,
},
{
path: 'plan/create',
name: "createFucTest",
component: EditFunctionalTestPlan,
},
{
path: "plan/edit/:testId",
component: EditFunctionalTestPlan,
props: {
content: (route) => {
return {
...route.params
}
}
}
},
{
path: "plan/:projectId",
component: FunctionalTestPlan
},
{
path: "project/:type",
component: MsProject
},
{
path: "report/:type",
component: FunctionalTestReport
}
}
]
},
{
path: "/loadtest/:projectId",
name: "loadtest",
path: "/performance",
name: "performance",
redirect: "/performance/home",
components: {
content: AllTestPlan
content: PerformanceTest
},
},
{
path: "/project/:type",
name: 'project',
components: {
content: MsProject
}
},
{
path: "/report/:type",
name: 'report',
components: {
content: AllTestReport
}
},
{
path: "/chart",
name: 'chart',
components: {
content: MsChart
}
children: [
{
path: 'home',
component: PerformanceTestHome,
},
{
path: 'plan/create',
name: "createPerTest",
component: EditPerformanceTestPlan,
},
{
path: "plan/edit/:testId",
component: EditPerformanceTestPlan,
props: {
content: (route) => {
return {
...route.params
}
}
}
},
{
path: "plan/:projectId",
component: PerformanceTestPlan
},
{
path: "project/:type",
component: MsProject
},
{
path: "report/:type",
component: PerformanceTestReport
},
{
path: "chart",
component: PerformanceChart
}
]
}
]
});

View File

@ -1,5 +1,5 @@
<template>
<div class="edit-testplan-container" v-loading="result.loading">
<div class="edit-testplan-container" >
<div class="main-content">
<el-card>
<el-row>
@ -20,16 +20,12 @@
<el-button type="warning" plain @click="cancel">{{$t('commons.cancel')}}</el-button>
</el-row>
<el-tabs class="testplan-config" v-model="active" type="border-card" :stretch="true">
<el-tab-pane :label="$t('load_test.basic_config')">
<ms-test-plan-basic-config :test-plan="testPlan" ref="basicConfig"/>
<functional-test-scene-config :test-plan="testPlan" />
</el-tab-pane>
<el-tab-pane :label="$t('load_test.pressure_config')">
<ms-test-plan-pressure-config :test-plan="testPlan" ref="pressureConfig"/>
</el-tab-pane>
<el-tab-pane :label="$t('load_test.advanced_config')" class="advanced-config">
<ms-test-plan-advanced-config ref="advancedConfig"/>
<el-tab-pane :label="$t('load_test.runtime_config')">
<functional-test-runtime-config :test-plan="testPlan" />
</el-tab-pane>
</el-tabs>
</el-card>
@ -38,16 +34,14 @@
</template>
<script>
import MsTestPlanBasicConfig from './components/BasicConfig';
import MsTestPlanPressureConfig from './components/PressureConfig';
import MsTestPlanAdvancedConfig from './components/AdvancedConfig';
import FunctionalTestSceneConfig from './components/FunctionalTestSceneConfig';
import FunctionalTestRuntimeConfig from './components/FunctionalTestRuntimeConfig';
export default {
name: "MsEditTestPlan",
name: "EditFunctionalTestPlan",
components: {
MsTestPlanBasicConfig,
MsTestPlanPressureConfig,
MsTestPlanAdvancedConfig,
FunctionalTestSceneConfig,
FunctionalTestRuntimeConfig,
},
data() {
return {
@ -77,19 +71,21 @@
watch: {
'$route'(to) {
//
if (to.name === 'createTest') {
if (to.name === 'createFucTest') {
window.location.reload();
return;
}
let testId = to.path.split('/')[2]; // find testId
this.$get('/testplan/get/' + testId, response => {
this.testPlan = response.data;
});
let testId = to.path.split('/')[4]; // find testId
if (testId) {
this.$get('/testplan/get/' + testId, response => {
this.testPlan = response.data;
});
}
}
},
created() {
let testId = this.$route.path.split('/')[2];
let testId = this.$route.path.split('/')[4];
if (testId) {
this.$get('/testplan/get/' + testId, response => {
this.testPlan = response.data;

View File

@ -0,0 +1,252 @@
<template>
<div class="edit-testplan-container" v-loading="result.loading">
<div class="main-content">
<el-card>
<el-row>
<el-col :span="10">
<el-input :placeholder="$t('load_test.input_name')" v-model="testPlan.name" class="input-with-select">
<el-select v-model="testPlan.projectId" slot="prepend" :placeholder="$t('load_test.select_project')">
<el-option
v-for="item in projects"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
</el-input>
</el-col>
<el-button type="primary" plain @click="save">{{$t('commons.save')}}</el-button>
<el-button type="primary" plain @click="saveAndRun">{{$t('load_test.save_and_run')}}</el-button>
<el-button type="warning" plain @click="cancel">{{$t('commons.cancel')}}</el-button>
</el-row>
<el-tabs class="testplan-config" v-model="active" type="border-card" :stretch="true">
<el-tab-pane :label="$t('load_test.basic_config')">
<performance-basic-config :test-plan="testPlan" ref="basicConfig"/>
</el-tab-pane>
<el-tab-pane :label="$t('load_test.pressure_config')">
<performance-pressure-config :test-plan="testPlan" ref="pressureConfig"/>
</el-tab-pane>
<el-tab-pane :label="$t('load_test.advanced_config')" class="advanced-config">
<performance-advanced-config ref="advancedConfig"/>
</el-tab-pane>
</el-tabs>
</el-card>
</div>
</div>
</template>
<script>
import PerformanceBasicConfig from "./components/PerformanceBasicConfig";
import PerformancePressureConfig from "./components/PerformancePressureConfig";
import PerformanceAdvancedConfig from "./components/PerformanceAdvancedConfig";
export default {
name: "EditPerformanceTestPlan",
components: {
PerformancePressureConfig,
PerformanceBasicConfig,
PerformanceAdvancedConfig
},
data() {
return {
result: {},
testPlan: {},
listProjectPath: "/project/listAll",
savePath: "/testplan/save",
editPath: "/testplan/edit",
runPath: "/testplan/run",
projects: [],
active: '0',
tabs: [{
title: this.$t('load_test.basic_config'),
id: '0',
component: 'PerformanceBasicConfig'
}, {
title: this.$t('load_test.pressure_config'),
id: '1',
component: 'PerformancePressureConfig'
}, {
title: this.$t('load_test.advanced_config'),
id: '2',
component: 'PerformanceAdvancedConfig'
}]
}
},
watch: {
'$route'(to) {
//
if (to.name === 'createPerTest') {
window.location.reload();
return;
}
let testId = to.path.split('/')[4]; // find testId
if (testId) {
this.$get('/testplan/get/' + testId, response => {
this.testPlan = response.data;
});
}
}
},
created() {
let testId = this.$route.path.split('/')[4];
if (testId) {
this.$get('/testplan/get/' + testId, response => {
this.testPlan = response.data;
});
}
this.listProjects();
},
methods: {
listProjects() {
this.result = this.$get(this.listProjectPath, response => {
this.projects = response.data;
})
},
save() {
if (!this.validTestPlan()) {
return;
}
let options = this.getSaveOption();
this.result = this.$request(options, () => {
this.$message({
message: this.$t('commons.save_success'),
type: 'success'
});
this.$refs.advancedConfig.cancelAllEdit();
this.$router.push({path: '/performance/plan/all'})
});
},
saveAndRun() {
if (!this.validTestPlan()) {
return;
}
let options = this.getSaveOption();
this.result = this.$request(options, (response) => {
this.testPlan.id = response.data;
this.$message({
message: this.$t('commons.save_success'),
type: 'success'
});
this.result = this.$post(this.runPath, {id: this.testPlan.id}, () => {
this.$message({
message: this.$t('load_test.is_running'),
type: 'success'
});
})
});
},
getSaveOption() {
let formData = new FormData();
let url = this.testPlan.id ? this.editPath : this.savePath;
if (!this.testPlan.file.id) {
formData.append("file", this.testPlan.file);
}
//
this.testPlan.loadConfiguration = JSON.stringify(this.$refs.pressureConfig.convertProperty());
//
this.testPlan.advancedConfiguration = JSON.stringify(this.$refs.advancedConfig.configurations());
// filejson
let requestJson = JSON.stringify(this.testPlan, function (key, value) {
return key === "file" ? undefined : value
});
formData.append('request', new Blob([requestJson], {
type: "application/json"
}));
return {
method: 'POST',
url: url,
data: formData,
headers: {
'Content-Type': undefined
}
};
},
cancel() {
this.$router.push({path: '/performance/plan/all'})
},
validTestPlan() {
if (!this.testPlan.name) {
this.$message({
message: this.$t('load_test.test_name_is_null'),
type: 'error'
});
return false;
}
if (!this.testPlan.projectId) {
this.$message({
message: this.$t('load_test.project_is_null'),
type: 'error'
});
return false;
}
if (!this.testPlan.file) {
this.$message({
message: this.$t('load_test.jmx_is_null'),
type: 'error'
});
return false;
}
if (!this.$refs.advancedConfig.validConfig()) {
return false;
}
/// todo:
return true;
}
}
}
</script>
<style scoped>
.edit-testplan-container {
float: none;
text-align: center;
padding: 15px;
width: 100%;
height: 100%;
box-sizing: border-box;
}
.edit-testplan-container .main-content {
margin: 0 auto;
width: 100%;
max-width: 1200px;
}
.edit-testplan-container .testplan-config {
margin-top: 15px;
}
.el-select {
min-width: 130px;
}
.edit-testplan-container .input-with-select .el-input-group__prepend {
background-color: #fff;
}
.advanced-config {
height: calc(100vh - 280px);
overflow: auto;
}
</style>

View File

@ -14,7 +14,7 @@
import {ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "../../../common/constants";
export default {
name: "MsRecentTestPlan",
name: "PerformanceRecentTestPlan",
mounted() {
const rolesString = localStorage.getItem("roles");
const roles = rolesString.split(',');

View File

@ -0,0 +1,31 @@
<template>
<el-col>
<header-menus :beaseUrl="beaseUrl"/>
<div>
<transition>
<keep-alive>
<router-view/>
</keep-alive>
</transition>
</div>
</el-col>
</template>
<script>
import HeaderMenus from "../HeaderMenus";
export default {
name: "FunctionalTest",
components: {HeaderMenus},
data() {
return {
beaseUrl: "functional"
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,16 @@
<template>
<div>
<h1>性能测试首页</h1>
</div>
</template>
<script>
export default {
name: "PerformanceTestHome"
}
</script>
<style scoped>
</style>

View File

@ -139,7 +139,7 @@
},
handleEdit(testPlan) {
this.$router.push({
path: '/editTest/' + testPlan.id,
path: '/performance/plan/edit/' + testPlan.id,
})
},
handleDelete(testPlan) {

View File

@ -0,0 +1,42 @@
<template>
<el-menu router menu-trigger="click" :default-active="$route.path">
<div class="recent-text">
<i class="el-icon-time"/>
{{$t('load_test.recent')}}
</div>
<el-menu-item :key="t.id" v-for="t in recentTestPlans" :index="'/editTest/' + t.id">
{{ t.name }}
</el-menu-item>
</el-menu>
</template>
<script>
import {ROLE_TEST_MANAGER, ROLE_TEST_USER, ROLE_TEST_VIEWER} from "../../../common/constants";
export default {
name: "PerformanceRecentTestPlan",
mounted() {
const rolesString = localStorage.getItem("roles");
const roles = rolesString.split(',');
if (roles.indexOf(ROLE_TEST_MANAGER) > -1 || roles.indexOf(ROLE_TEST_USER) > -1 || roles.indexOf(ROLE_TEST_VIEWER) > -1) {
this.$get('/testplan/recent/5', (response) => {
this.recentTestPlans = response.data;
});
}
},
data() {
return {
recentTestPlans: []
}
}
}
</script>
<style scoped>
.recent-text {
padding-left: 10%;
color: #777777;
}
</style>

View File

@ -0,0 +1,32 @@
<template>
<el-col>
<header-menus :beaseUrl="beaseUrl"/>
<div>
<transition>
<keep-alive>
<router-view/>
</keep-alive>
</transition>
</div>
</el-col>
</template>
<script>
import HeaderMenus from "../HeaderMenus";
export default {
name: "PerformanceTest",
components: {HeaderMenus},
data() {
return {
beaseUrl: "performance"
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,16 @@
<template>
<div>
<h1>性能测试首页</h1>
</div>
</template>
<script>
export default {
name: "PerformanceTestHome"
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,195 @@
<template>
<div class="testplan-container" v-loading="result.loading">
<div class="main-content">
<el-card>
<div slot="header">
<el-row type="flex" justify="space-between" align="middle">
<span class="title">{{$t('commons.test')}}</span>
<span class="search">
<el-input type="text" size="small" :placeholder="$t('load_test.search_by_name')"
prefix-icon="el-icon-search"
maxlength="60"
v-model="condition" @change="search" clearable/>
</span>
</el-row>
</div>
<el-table :data="tableData" class="test-content">
<el-table-column
prop="name"
:label="$t('commons.name')"
width="150"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="description"
:label="$t('commons.description')"
show-overflow-tooltip>
</el-table-column>
<el-table-column
prop="projectName"
:label="$t('load_test.project_name')"
width="150"
show-overflow-tooltip>
</el-table-column>
<el-table-column
width="250"
:label="$t('commons.create_time')">
<template slot-scope="scope">
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
width="250"
:label="$t('commons.update_time')">
<template slot-scope="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
width="150"
:label="$t('commons.operating')">
<template slot-scope="scope">
<el-button @click="handleEdit(scope.row)" type="primary" icon="el-icon-edit" size="mini" circle/>
<el-button @click="handleDelete(scope.row)" type="danger" icon="el-icon-delete" size="mini" circle/>
</template>
</el-table-column>
</el-table>
<div>
<el-row>
<el-col :span="22" :offset="1">
<div class="table-page">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="currentPage"
:page-sizes="[5, 10, 20, 50, 100]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</el-col>
</el-row>
</div>
</el-card>
</div>
</div>
</template>
<script>
export default {
data() {
return {
result: {},
queryPath: "/testplan/list",
deletePath: "/testplan/delete",
condition: "",
projectId: null,
tableData: [],
multipleSelection: [],
currentPage: 1,
pageSize: 5,
total: 0,
loading: false,
testId: null,
}
},
watch: {
'$route'(to) {
this.projectId = to.params.projectId;
this.initTableData();
}
},
created: function () {
this.projectId = this.$route.params.projectId;
this.initTableData();
},
methods: {
initTableData() {
let param = {
name: this.condition,
};
if (this.projectId !== 'all') {
param.projectId = this.projectId;
}
this.result = this.$post(this.buildPagePath(this.queryPath), param, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
});
},
search() {
this.initTableData();
},
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
},
handleSizeChange(size) {
this.pageSize = size;
this.initTableData();
},
handleCurrentChange(current) {
this.currentPage = current;
this.initTableData();
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleEdit(testPlan) {
this.$router.push({
path: '/performance/plan/edit/' + testPlan.id,
})
},
handleDelete(testPlan) {
this.$alert(this.$t('load_test.delete_confirm') + testPlan.name + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this._handleDelete(testPlan);
}
}
});
},
_handleDelete(testPlan) {
let data = {
id: testPlan.id
};
this.result = this.$post(this.deletePath, data, () => {
this.$message({
message: this.$t('commons.delete_success'),
type: 'success'
});
this.initTableData();
});
},
}
}
</script>
<style scoped>
.testplan-container {
padding: 15px;
width: 100%;
height: 100%;
box-sizing: border-box;
}
.main-content {
margin: 0 auto;
width: 100%;
max-width: 1200px;
}
.test-content {
width: 100%;
}
.table-page {
padding-top: 20px;
margin-right: -9px;
float: right;
}
</style>

View File

@ -0,0 +1,16 @@
<template>
<div>
</div>
</template>
<script>
export default {
name: "FunctionalTestRuntimeConfig"
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,16 @@
<template>
<div>
</div>
</template>
<script>
export default {
name: "FunctionalTestSceneConfig"
}
</script>
<style scoped>
</style>

View File

@ -200,7 +200,7 @@
<script>
export default {
name: "MsTestPlanAdvancedConfig",
name: "PerformanceAdvancedConfig",
data() {
return {
timeout: 10,
@ -211,14 +211,14 @@
}
},
mounted() {
let testId = this.$route.path.split('/')[2];
let testId = this.$route.path.split('/')[4];
if (testId) {
this.getAdvancedConfig(testId);
}
},
watch: {
'$route'(to) {
let testId = to.path.split('/')[2];
let testId = to.path.split('/')[4];
if (testId) {
this.getAdvancedConfig(testId);
}

View File

@ -56,7 +56,7 @@
import {Message} from "element-ui";
export default {
name: "MsTestPlanBasicConfig",
name: "PerformanceBasicConfig",
props: ["testPlan"],
data() {
return {

View File

@ -92,7 +92,7 @@
const RPS_LIMIT = "rpsLimit";
export default {
name: "MsTestPlanPressureConfig",
name: "PerformancePressureConfig",
data() {
return {
testPlan: {},
@ -105,7 +105,7 @@
}
},
mounted() {
let testId = this.$route.path.split('/')[2];
let testId = this.$route.path.split('/')[4];
if (testId) {
this.getLoadConfig(testId);
} else {
@ -114,7 +114,7 @@
},
watch: {
'$route'(to) {
let testId = to.path.split('/')[2];
let testId = to.path.split('/')[4];
if (testId) {
this.getLoadConfig(testId);
} else {