Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Captain.B 2020-04-29 11:11:31 +08:00
commit cc8c646faf
11 changed files with 460 additions and 6 deletions

View File

@ -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

View File

@ -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\":{}}}");

View File

@ -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

View File

@ -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
}
]
},

View File

@ -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>

View File

@ -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">

View File

@ -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>

View File

@ -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>

View File

@ -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);

3
package-lock.json generated
View File

@ -1,3 +0,0 @@
{
"lockfileVersion": 1
}