Merge branch 'dev' of github.com:fit2cloudrd/metersphere-server into dev

This commit is contained in:
Captain.B 2020-03-12 16:35:37 +08:00
commit 3725a267f0
32 changed files with 1205 additions and 230 deletions

View File

@ -40,7 +40,9 @@
"plugin:vue/essential",
"eslint:recommended"
],
"rules": {},
"rules": {
"vue/no-unused-components": "off"
},
"parserOptions": {
"parser": "babel-eslint"
}

View File

@ -117,6 +117,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

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

View File

@ -11,39 +11,23 @@
<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']" v-if="isCurrentWorkspaceUser">
<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";
import MsWebSocket from "./components/websocket/WebSocket";
import {checkoutCurrentWorkspace} from "../common/utils";
export default {
name: 'app',
data() {
return {
auth: false,
isCurrentWorkspaceUser: false,
auth: false
}
},
beforeCreate() {
@ -59,11 +43,8 @@
window.location.href = "/login"
});
},
components: {MsWebSocket, MsUser, MsMenus, MsView, MsTopMenus},
methods: {},
mounted() {
this.isCurrentWorkspaceUser = checkoutCurrentWorkspace();
}
components: {MsWebSocket, MsUser, MsView, MsTopMenus},
methods: {}
}
</script>
@ -96,14 +77,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,87 +1,120 @@
<template>
<div id="menu-bar">
<el-menu class="header-menu" :unique-opened="true" mode="horizontal" router
:default-active='$route.path'>
<el-menu-item index="/setting/personsetting">
<el-menu-item :index="'/' + beaseUrl + '/home'">
{{ $t("i18n.home") }}
</el-menu-item>
<el-submenu index="3" popper-class="submenu" v-permission="['test_manager']" v-if="isCurrentWorkspaceUser">
<template slot="title">{{$t('commons.project')}}</template>
<ms-recent-project/>
<performance-recent-project v-if="beaseUrl == 'performance'"/>
<functional-recent-project v-if="beaseUrl == 'functional'"/>
<el-divider/>
<el-menu-item index="/project/all">
<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="/project/create">
<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']"
v-if="isCurrentWorkspaceUser">
<template slot="title">{{$t('commons.test')}}</template>
<ms-recent-test-plan/>
<performance-recent-test-plan v-if="beaseUrl == 'performance'"/>
<functional-recent-test-plan v-if="beaseUrl == 'functional'"/>
<el-divider/>
<el-menu-item index="/loadtest/all">
<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="/createTest">
<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']"
v-if="isCurrentWorkspaceUser">
<template slot="title">{{$t('commons.report')}}</template>
<ms-recent-report/>
<performance-recent-report v-if="beaseUrl == 'performance'"/>
<functional-recent-report v-if="beaseUrl == 'functional'"/>
<el-divider/>
<el-menu-item index="/report/all">
<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']"
v-if="isCurrentWorkspaceUser">
<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 MsRecentProject from "./project/RecentProject";
import MsRecentReport from "./report/RecentReport";
import PerformanceRecentTestPlan from "./testPlan/PerformanceRecentTestPlan";
import FunctionalRecentTestPlan from "./testPlan/FunctionalRecentTestPlan";
import PerformanceRecentProject from "./project/PerformanceRecentProject";
import FunctionalRecentProject from "./project/FunctionalRecentProject";
import PerformanceRecentReport from "./report/PerformanceRecentReport";
import FunctionalRecentReport from "./report/FunctionalRecentReport";
import {checkoutCurrentWorkspace} from "../../common/utils";
export default {
name: "MsMenus",
components: {MsRecentReport, MsRecentTestPlan, MsRecentProject},
components: {PerformanceRecentReport, PerformanceRecentTestPlan, FunctionalRecentTestPlan, FunctionalRecentReport,
PerformanceRecentProject,FunctionalRecentProject},
data() {
return {
isCurrentWorkspaceUser: false,
}
},
props: {
beaseUrl: {
type: String
}
},
mounted() {
this.isCurrentWorkspaceUser = checkoutCurrentWorkspace();
}
}
</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,11 @@
: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']">
{{$t('commons.functional')}}
</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']">
{{$t('commons.performance')}}
</el-menu-item>

View File

@ -6,7 +6,7 @@
</div>
<el-menu-item :key="p.id" v-for="p in recentProjects"
:index="'/loadtest/' + p.id" :route="{name:'loadtest', params:{projectId:p.id, projectName:p.name}}">
:index="'/functional/' + p.id" :route="{name:'fucPlan', params:{projectId:p.id, projectName:p.name}}">
{{ p.name }}
</el-menu-item>
</el-menu>
@ -18,7 +18,7 @@
import {hasRoles} from "../../../common/utils";
export default {
name: "MsRecentProject",
name: "FunctionalRecentProject",
mounted() {
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {

View File

@ -90,18 +90,23 @@
},
}
},
props: {
beaseUrl: {
type: String
}
},
mounted() {
if (this.$route.path.split('/')[2] === 'create') {
if (this.$route.path.split('/')[3] === 'create') {
this.create();
this.$router.push('/project/all');
this.$router.push( '/' + this.beaseUrl + '/project/all');
}
this.list();
},
watch: {
'$route'(to) {
if (to.path.split('/')[2] === 'create') {
if (to.path.split('/')[3] === 'create') {
this.create();
this.$router.push('/project/all');
this.$router.push('/' + this.beaseUrl + '/project/all');
}
}
},

View File

@ -6,7 +6,7 @@
import echarts from 'echarts'
export default {
name: "MsChart",
name: "PerformanceChart",
data() {
return {
bar: {

View File

@ -0,0 +1,44 @@
<template>
<el-menu router menu-trigger="click" :default-active="$route.path">
<div class="recent-text">
<i class="el-icon-time"/>
{{$t('project.recent')}}
</div>
<el-menu-item :key="p.id" v-for="p in recentProjects"
:index="'/performance/plan/' + p.id" :route="{name:'perPlan', 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";
import {hasRoles} from "../../../common/utils";
export default {
name: "PerformanceRecentProject",
mounted() {
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
this.$get('/project/recent/5', (response) => {
this.recentProjects = response.data;
});
}
},
methods: {},
data() {
return {
recentProjects: [],
}
}
}
</script>
<style scoped>
.recent-text {
padding-left: 10%;
color: #777777;
}
</style>

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="'/functional/report/view/' + p.id" :route="{path: '/functional/report/view/' + p.id}">
{{ 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,185 @@
<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: "FunctionalTestReport",
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(report) {
this.$router.push({
path: '/functional/reportView/' + report.id
})
},
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

@ -5,7 +5,7 @@
{{$t('load_test.recent')}}
</div>
<el-menu-item :key="p.id" v-for="p in recentReports"
:index="'/reportView/' + p.id" :route="{path: '/reportView/' + p.id}">
:index="'/performance/report/view/' + p.id" :route="{path: '/performance/report/view/' + p.id}">
{{ p.name }}
</el-menu-item>
</el-menu>
@ -16,7 +16,7 @@
import {hasRoles} from "../../../common/utils";
export default {
name: "MsRecentReport",
name: "PerformanceRecentReport",
mounted() {
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {

View File

@ -60,7 +60,7 @@
import MsReportTestOverview from './components/TestOverview';
export default {
name: "ReportView",
name: "PerformanceReportView",
components: {
MsReportErrorLog,
MsReportLogDetails,
@ -79,30 +79,38 @@
},
methods: {
initBreadcrumb() {
if(this.reportId){
this.result = this.$get("report/test/pro/info/" + this.reportId, res => {
let data = res.data;
if(data){
this.reportName = data.name;
this.testName = data.testName;
this.projectName = data.projectName;
}
})
}
}
},
created() {
this.reportId = this.$route.path.split('/')[2];
this.reportId = this.$route.path.split('/')[4];
this.initBreadcrumb();
},
watch: {
'$route'(to) {
let reportId = to.path.split('/')[2]; // find testId
let reportId = to.path.split('/')[4];
if(reportId){
this.$get("report/test/pro/info/" + reportId, response => {
let data = response.data;
if(data){
this.reportName = data.name;
this.testName = data.testName;
this.projectName = data.projectName;
}
});
}
}
}
}
</script>
<style scoped>

View File

@ -48,11 +48,11 @@
</template>
</el-table-column>
<el-table-column
width="200"
width="150"
:label="$t('commons.operating')">
<template slot-scope="scope">
<el-button @click="handleEdit(scope.row)" type="primary" size="mini">查看</el-button>
<el-button @click="handleDelete(scope.row)" type="danger" size="mini">删除</el-button>
<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>
@ -81,7 +81,7 @@
<script>
export default {
name: "MsAllTestReport",
name: "PerformanceTestReport",
created: function () {
this.initTableData();
},
@ -131,7 +131,7 @@
},
handleEdit(report) {
this.$router.push({
path: '/reportView/' + report.id
path: '/performance/report/view/' + report.id
})
},
handleDelete(report) {

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,9 +13,16 @@ 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 ReportView from "../report/ReportView";
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";
import PerformanceReportView from "../report/PerformanceReportView";
Vue.use(VueRouter);
@ -69,18 +76,27 @@ const router = new VueRouter({
]
},
{
path: "/createTest",
name: "createTest",
path: "/functional",
name: "functional",
redirect: "/functional/home",
components: {
content: EditTestPlan
}
content: FunctionalTest
},
children: [
{
path: 'home',
name: 'fucHome',
component: FunctionalTestHome,
},
{
path: "/editTest/:testId",
name: "editTest",
components: {
content: EditTestPlan
path: 'plan/create',
name: "createFucTest",
component: EditFunctionalTestPlan,
},
{
path: "plan/edit/:testId",
name: "editFucTest",
component: EditFunctionalTestPlan,
props: {
content: (route) => {
return {
@ -90,40 +106,79 @@ const router = new VueRouter({
}
},
{
path: "/loadtest/:projectId",
name: "loadtest",
components: {
content: AllTestPlan
},
path: "plan/:projectId",
name: "fucPlan",
component: FunctionalTestPlan
},
{
path: "/project/:type",
name: 'project',
path: "project/:type",
name: "fucProject",
component: MsProject
},
{
path: "report/:type",
name: "fucReport",
component: FunctionalTestReport
}
]
},
{
path: "/performance",
name: "performance",
redirect: "/performance/home",
components: {
content: MsProject
content: PerformanceTest
},
children: [
{
path: 'home',
name: 'perHome',
component: PerformanceTestHome,
},
{
path: 'plan/create',
name: "createPerTest",
component: EditPerformanceTestPlan,
},
{
path: "plan/edit/:testId",
name: "editPerTest",
component: EditPerformanceTestPlan,
props: {
content: (route) => {
return {
...route.params
}
}
}
},
{
path: "/report/:type",
name: 'report',
components: {
content: AllTestReport
}
path: "plan/:projectId",
name: "perPlan",
component: PerformanceTestPlan
},
{
path: "/chart",
name: 'chart',
components: {
content: MsChart
}
path: "project/:type",
name: "perProject",
component: MsProject
},
{
path: "/reportView/:reportId",
name: "reportView",
components: {
content: ReportView
}
path: "report/:type",
name: "perReport",
component: PerformanceTestReport
},
{
path: "chart",
name: "perChart",
component: PerformanceChart
},
{
path: "report/view/:reportId",
name: "perReportView",
component: PerformanceReportView
}
]
}
]
});

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
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,255 @@
<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 => {
if(response.data){
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

@ -4,7 +4,7 @@
<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">
<el-menu-item :key="t.id" v-for="t in recentTestPlans" :index="'/functional/plan/edit/' + t.id">
{{ t.name }}
</el-menu-item>
</el-menu>
@ -15,7 +15,7 @@
import {hasRoles} from "../../../common/utils";
export default {
name: "MsRecentTestPlan",
name: "PerformanceRecentTestPlan",
mounted() {
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {

View File

@ -0,0 +1,31 @@
<template>
<el-col>
<header-menus :beaseUrl="beaseUrl"/>
<div>
<transition>
<keep-alive>
<router-view :beaseUrl="beaseUrl"/>
</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="'/performance/plan/edit/' + 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 :beaseUrl="beaseUrl"/>
</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,17 @@
}
},
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];
'$route'(to, from) {
if(from.name != 'createPerTest' || from.name != 'editPerTest'){
return;
}
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

@ -91,7 +91,7 @@
const RPS_LIMIT = "rpsLimit";
export default {
name: "MsTestPlanPressureConfig",
name: "PerformancePressureConfig",
data() {
return {
testPlan: {},
@ -104,7 +104,7 @@
}
},
mounted() {
let testId = this.$route.path.split('/')[2];
let testId = this.$route.path.split('/')[4];
if (testId) {
this.getLoadConfig(testId);
} else {
@ -112,8 +112,11 @@
}
},
watch: {
'$route'(to) {
let testId = to.path.split('/')[2];
'$route'(to, from) {
if(from.name != 'createPerTest' || from.name != 'editPerTest'){
return;
}
let testId = to.path.split('/')[4];
if (testId) {
this.getLoadConfig(testId);
} else {
@ -123,8 +126,10 @@
},
methods: {
getLoadConfig(testId) {
if(testId) {
this.$get('/testplan/get-load-config/' + testId, (response) => {
if (response.data) {
if (response.data && response.data != "") {
let data = JSON.parse(response.data);
data.forEach(d => {
@ -158,6 +163,7 @@
this.calculateChart();
}
});
}
},
calculateChart() {
if (this.duration < this.rampUpTime) {