Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
cc8c646faf
|
@ -319,4 +319,29 @@ CREATE TABLE IF NOT EXISTS `test_plan_test_case` (
|
|||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_bin;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `test_case_report_template` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(64) NOT NULL COMMENT 'Test case report template name',
|
||||
`workspace_id` varchar(50) DEFAULT NULL COMMENT 'Workspace ID this project belongs to',
|
||||
`content` longtext COMMENT 'Template content (JSON format)',
|
||||
PRIMARY KEY (`id`)
|
||||
)
|
||||
ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_bin;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `test_case_report` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(64) NOT NULL COMMENT 'Test case report name',
|
||||
`plan_id` bigint(50) DEFAULT NULL COMMENT 'Plan ID relation to',
|
||||
`content` longtext COMMENT 'Report content (JSON format)',
|
||||
PRIMARY KEY (`id`)
|
||||
)
|
||||
ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_bin;
|
||||
|
||||
-- track end
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -10,3 +10,4 @@ INSERT INTO role (id, name, description, type, create_time, update_time) VALUES
|
|||
INSERT INTO role (id, name, description, type, create_time, update_time) VALUES ('test_user', '测试人员', null, null, 1581576575948, 1581576575948);
|
||||
INSERT INTO role (id, name, description, type, create_time, update_time) VALUES ('test_viewer', 'Viewer', null, null, 1581576575948, 1581576575948);
|
||||
|
||||
INSERT INTO test_case_report_template (name,content) VALUES ("默认模版","{\"components\":[1,2,3,4,5],\"contentMap\":{\"richTextComponentTitleSet\":{},\"richTextComponentContentSet\":{}}}");
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ckeditor/ckeditor5-build-classic": "^18.0.0",
|
||||
"@ckeditor/ckeditor5-vue": "^1.0.1",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.26",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.12.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.12.0",
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
|
@ -8,6 +8,7 @@ import PerformanceTestPlan from "../../performance/test/PerformanceTestPlan";
|
|||
import Organization from "../../settings/system/Organization";
|
||||
import OrganizationMember from "../../settings/organization/OrganizationMember";
|
||||
import Member from "../../settings/workspace/WorkspaceMember";
|
||||
import TestCaseReportTemplate from "../../settings/workspace/TestCaseReportTemplate";
|
||||
import TestResourcePool from "../../settings/system/TestResourcePool";
|
||||
import MsProject from "../../project/MsProject";
|
||||
import OrganizationWorkspace from "../../settings/organization/OrganizationWorkspace";
|
||||
|
@ -78,6 +79,10 @@ const router = new VueRouter({
|
|||
{
|
||||
path: 'testresourcepool',
|
||||
component: TestResourcePool
|
||||
},
|
||||
{
|
||||
path: 'testcase/report/template',
|
||||
component: TestCaseReportTemplate
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
stripe
|
||||
border
|
||||
style="width: 100%"
|
||||
:default-sort = "{prop: 'samples', order: 'descending'}"
|
||||
show-summary
|
||||
:summary-method="getSummaries"
|
||||
>
|
||||
<el-table-column label="Requests" fixed width="450" align="center">
|
||||
<el-table-column
|
||||
|
@ -103,6 +104,54 @@
|
|||
this.tableData = res.data;
|
||||
})
|
||||
},
|
||||
getSummaries(param) {
|
||||
const {data} = param;
|
||||
const sums = []
|
||||
let allSamples = data.reduce(function (total, currentValue) {
|
||||
return total + parseFloat(currentValue.samples);
|
||||
}, 0);
|
||||
let failSize = data.reduce(function (total, currentValue) {
|
||||
return total + parseFloat(currentValue.ko);
|
||||
}, 0);
|
||||
let averageTimeTotal = data.reduce(function (total, currentValue) {
|
||||
return total + parseFloat(currentValue.average) * parseFloat(currentValue.samples);
|
||||
}, 0);
|
||||
let tp90Total = data.reduce(function (total, currentValue) {
|
||||
return total + parseFloat(currentValue.tp90) * parseFloat(currentValue.samples);
|
||||
}, 0);
|
||||
let tp95Total = data.reduce(function (total, currentValue) {
|
||||
return total + parseFloat(currentValue.tp95) * parseFloat(currentValue.samples);
|
||||
}, 0);
|
||||
let tp99Total = data.reduce(function (total, currentValue) {
|
||||
return total + parseFloat(currentValue.tp99) * parseFloat(currentValue.samples);
|
||||
}, 0);
|
||||
let transactions = data.reduce(function (total, currentValue) {
|
||||
return total + parseFloat(currentValue.transactions);
|
||||
}, 0);
|
||||
let received = data.reduce(function (total, currentValue) {
|
||||
return total + parseFloat(currentValue.received);
|
||||
}, 0);
|
||||
let sent = data.reduce(function (total, currentValue) {
|
||||
return total + parseFloat(currentValue.sent);
|
||||
}, 0);
|
||||
|
||||
let error = (Math.round(failSize / allSamples * 10000) / 100) + '%';
|
||||
let averageTime = (averageTimeTotal / allSamples).toFixed(2);
|
||||
let tp90 = (tp90Total / allSamples).toFixed(2);
|
||||
let tp95 = (tp95Total / allSamples).toFixed(2);
|
||||
let tp99 = (tp99Total / allSamples).toFixed(2);
|
||||
let min = Math.min.apply(Math, data.map(function (o) {
|
||||
return parseFloat(o.min)
|
||||
}));
|
||||
let max = Math.max.apply(Math, data.map(function (o) {
|
||||
return parseFloat(o.max)
|
||||
}));
|
||||
|
||||
sums.push('Total', allSamples, failSize, error, averageTime, min, max, tp90, tp95, tp99, transactions, received, sent);
|
||||
|
||||
return sums;
|
||||
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
status() {
|
||||
|
@ -111,7 +160,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
props: ['id','status']
|
||||
props: ['id', 'status']
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
<span>{{$t('commons.workspace')}}</span>
|
||||
</template>
|
||||
<el-menu-item index="/setting/member">{{$t('commons.member')}}</el-menu-item>
|
||||
<el-menu-item index="/setting/testcase/report/template">测试报告模版</el-menu-item>
|
||||
</el-submenu>
|
||||
|
||||
<el-submenu index="4">
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
<template>
|
||||
|
||||
<div v-loading="result.loading">
|
||||
<el-card>
|
||||
<template v-slot:header>
|
||||
<ms-table-header :condition.sync="condition" @search="initTableData"
|
||||
:title="'测试报告模版'"
|
||||
:create-tip="'新建模版'" @create="templateEdit">
|
||||
|
||||
</ms-table-header>
|
||||
</template>
|
||||
|
||||
<el-main>
|
||||
<div class="testcase-template" v-for="fit in fits" :key="fit">
|
||||
<div class="template-img">
|
||||
<i class="el-icon-error"/>
|
||||
</div>
|
||||
<span class="demonstration">{{ fit }}</span>
|
||||
</div>
|
||||
</el-main>
|
||||
|
||||
<test-case-report-template-edit ref="templateEdit"/>
|
||||
|
||||
</el-card>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import MsTableHeader from "../../common/components/MsTableHeader";
|
||||
import TestCaseReportTemplateEdit from "./components/TestCaseReportTemplateEdit";
|
||||
export default {
|
||||
name: "TestCaseReportTemplate",
|
||||
components: {TestCaseReportTemplateEdit, MsTableHeader},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
fits: ['默认模版', 'congewtain', 'cogewver', 'nongwee', 'scale-downddddddddddd',
|
||||
'faill', 'cdontain', 'codver', 'nodne', 'scalde-downddddddddddd',
|
||||
'fill', 'cowntain', 'corwver',
|
||||
'nonewbe',
|
||||
'scalev-downddddddddddd',
|
||||
'filelv', 'sontwain', 'cosgewver', 'nodegne', 'scale-dfownddddddddddd',
|
||||
],
|
||||
url: '../../../../assets/template.png',
|
||||
condition: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initTableData() {
|
||||
|
||||
},
|
||||
templateCreate() {
|
||||
|
||||
},
|
||||
templateEdit() {
|
||||
this.$refs.templateEdit.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.testcase-template {
|
||||
display: inline-block;
|
||||
margin: 10px 30px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.demonstration {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin: 10px auto;
|
||||
width: 150px;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
text-overflow:ellipsis;
|
||||
}
|
||||
|
||||
.template-img {
|
||||
height: 100px;
|
||||
width: 80px;
|
||||
margin: 0 auto;
|
||||
box-shadow: 0 0 2px 0 rgba(31,31,31,0.15), 0 1px 2px 0 rgba(31,31,31,0.15);
|
||||
border: solid 2px #fff;
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
background: url(../../../../assets/template.png) no-repeat center;
|
||||
}
|
||||
|
||||
.template-img:hover {
|
||||
border: solid 1px #4b8fdf;
|
||||
border-radius: 3px;
|
||||
color: deepskyblue;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.template-img > i {
|
||||
display:none;
|
||||
float: right;
|
||||
color: gray;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.template-img > i:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.template-img:hover > .el-icon-error {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,256 @@
|
|||
<template>
|
||||
|
||||
<el-drawer
|
||||
:before-close="handleClose"
|
||||
:visible.sync="showDialog"
|
||||
:with-header="false"
|
||||
size="100%"
|
||||
ref="drawer"
|
||||
v-loading="result.loading">
|
||||
|
||||
<template v-slot:default="scope">
|
||||
|
||||
<el-row type="flex" class="head-bar">
|
||||
|
||||
<el-col :span="12">
|
||||
|
||||
<div class="name-edit">
|
||||
<el-input :placeholder="'请填写模版名称'" v-model="name"/>
|
||||
<span v-if="name != ''">{{name}}</span>
|
||||
<span v-if="name == ''">请填写模版名称</span>
|
||||
</div>
|
||||
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="head-right">
|
||||
<el-button plain size="mini" @click="handleClose">{{$t('test_track.return')}}</el-button>
|
||||
<el-button type="primary" size="mini" @click="handleClose">{{$t('test_track.save')}}</el-button>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<el-scrollbar>
|
||||
|
||||
<div class="template-content">
|
||||
|
||||
<el-aside>
|
||||
|
||||
<div class="description">
|
||||
<span class="title">组件库</span>
|
||||
<span>从组件库把需要使用的组件拖到右侧,预览测试报告的效果。系统组件只能添加一次。自定义组件,可以设定默认的标题和内容。</span>
|
||||
</div>
|
||||
|
||||
<draggable
|
||||
class="component-group"
|
||||
:list="components"
|
||||
:group="{ name: 'people', pull: 'clone', put: false }"
|
||||
:clone="cloneDog"
|
||||
@change="log">
|
||||
<el-button class="template-component" v-for="item in components" :key="item.id">
|
||||
<i class="el-icon-s-unfold"/>
|
||||
<span>{{ item.name }}</span>
|
||||
<el-tag v-if="item.type == 'system'" size="mini" type="success">系统</el-tag>
|
||||
<el-tag v-if="item.type == 'custom'" size="mini">自定义</el-tag>
|
||||
</el-button>
|
||||
</draggable>
|
||||
|
||||
</el-aside>
|
||||
|
||||
<el-main>
|
||||
<el-row>
|
||||
<el-col>
|
||||
|
||||
<draggable
|
||||
class="preview-group"
|
||||
:list="previews"
|
||||
group="people"
|
||||
@change="log">
|
||||
<el-card class="template-component" v-for="item in previews" :key="item.id">
|
||||
|
||||
<template v-slot:header>
|
||||
{{item.name}}
|
||||
</template>
|
||||
|
||||
<ckeditor :editor="editor" v-model="editorData" :config="editorConfig"></ckeditor>
|
||||
|
||||
</el-card>
|
||||
</draggable>
|
||||
|
||||
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-main>
|
||||
|
||||
</div>
|
||||
|
||||
</el-scrollbar>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
</el-drawer>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import draggable from 'vuedraggable';
|
||||
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
|
||||
|
||||
let idGlobal = 8;
|
||||
export default {
|
||||
name: "TestCaseReportTemplateEdit",
|
||||
components: {
|
||||
draggable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
template: {},
|
||||
result: {},
|
||||
name: '',
|
||||
type: 'edit',
|
||||
components: [
|
||||
{ name: "dog 1", id: 1 , type: 'system'},
|
||||
{ name: "dog 2", id: 2 , type: 'custom'},
|
||||
{ name: "dog 3", id: 3 ,type: 'system'},
|
||||
{ name: "dog 4", id: 4 ,type: 'system'}
|
||||
],
|
||||
previews: [
|
||||
{ name: "cat 5", id: 5 },
|
||||
{ name: "cat 6", id: 6 },
|
||||
{ name: "cat 7", id: 7 }
|
||||
],
|
||||
|
||||
editor: ClassicEditor,
|
||||
editorData: '<p>Content of the editor.</p>',
|
||||
editorConfig: {
|
||||
// The configuration of the editor.
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open() {
|
||||
this.showDialog = true;
|
||||
},
|
||||
handleClose() {
|
||||
this.showDialog = false;
|
||||
},
|
||||
log: function(evt) {
|
||||
window.console.log(evt);
|
||||
},
|
||||
cloneDog({ id }) {
|
||||
return {
|
||||
id: idGlobal++,
|
||||
name: `cat ${id}`
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.head-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.head-bar {
|
||||
background: white;
|
||||
height: 45px;
|
||||
line-height: 45px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid #EBEEF5;
|
||||
box-shadow: 0 0 2px 0 rgba(31,31,31,0.15), 0 1px 2px 0 rgba(31,31,31,0.15);
|
||||
}
|
||||
|
||||
.name-edit:hover span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.name-edit .el-input {
|
||||
display: none;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.name-edit:hover .el-input{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.el-aside {
|
||||
border: 1px solid #EBEEF5;
|
||||
box-sizing: border-box;
|
||||
min-height: calc(100vh - 70px);
|
||||
padding: 20px 20px;
|
||||
border-radius: 3px;
|
||||
background: white;
|
||||
position: absolute;
|
||||
width: 250px;
|
||||
box-shadow: 0 0 2px 0 rgba(31,31,31,0.15), 0 1px 2px 0 rgba(31,31,31,0.15);
|
||||
}
|
||||
|
||||
.el-main {
|
||||
height: 1000px;
|
||||
margin-left: 300px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.template-component i {
|
||||
float: left;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.template-component .el-tag {
|
||||
float: right;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.template-component span {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.template-component {
|
||||
display: block;
|
||||
margin-left: 10px;
|
||||
width: 90%;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.el-card {
|
||||
margin: 5px auto;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.description > span {
|
||||
display: block;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.container {
|
||||
height: 100vh;
|
||||
background: #F5F5F5;
|
||||
}
|
||||
|
||||
.template-content {
|
||||
|
||||
}
|
||||
|
||||
.el-scrollbar {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
|
@ -14,6 +14,7 @@ import {permission} from './permission'
|
|||
import chart from "../common/js/chart";
|
||||
import '../common/css/menu-header.css';
|
||||
import '../common/css/main.css';
|
||||
import CKEditor from '@ckeditor/ckeditor5-vue';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
Vue.use(icon);
|
||||
|
@ -23,7 +24,8 @@ Vue.use(ElementUI, {
|
|||
Vue.use(filters);
|
||||
Vue.use(ajax);
|
||||
Vue.use(chart);
|
||||
Vue.use(message)
|
||||
Vue.use(message);
|
||||
Vue.use(CKEditor);
|
||||
|
||||
// v-permission
|
||||
Vue.directive('permission', permission);
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"lockfileVersion": 1
|
||||
}
|
Loading…
Reference in New Issue