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

This commit is contained in:
Captain.B 2020-04-23 18:51:55 +08:00
commit d0ddd8d869
31 changed files with 519 additions and 466 deletions

View File

@ -60,9 +60,9 @@ public class APITestController {
public void delete(@RequestBody DeleteAPITestRequest request) { public void delete(@RequestBody DeleteAPITestRequest request) {
apiTestService.delete(request); apiTestService.delete(request);
} }
//
// @PostMapping("/run") @PostMapping("/run")
// public void run(@RequestBody RunTestPlanRequest request) { public void run(@RequestBody SaveAPITestRequest request) {
// apiTestService.run(request); apiTestService.run(request);
// } }
} }

View File

@ -66,6 +66,10 @@ public class ApiTestService {
apiTestMapper.deleteByPrimaryKey(request.getId()); apiTestMapper.deleteByPrimaryKey(request.getId());
} }
public void run(SaveAPITestRequest request) {
save(request);
}
private ApiTestWithBLOBs updateTest(SaveAPITestRequest request) { private ApiTestWithBLOBs updateTest(SaveAPITestRequest request) {
final ApiTestWithBLOBs test = new ApiTestWithBLOBs(); final ApiTestWithBLOBs test = new ApiTestWithBLOBs();
test.setId(request.getId()); test.setId(request.getId());

View File

@ -14,13 +14,14 @@
"@fortawesome/vue-fontawesome": "^0.1.9", "@fortawesome/vue-fontawesome": "^0.1.9",
"axios": "^0.19.0", "axios": "^0.19.0",
"core-js": "^3.4.3", "core-js": "^3.4.3",
"echarts": "^4.6.0",
"element-ui": "^2.13.0", "element-ui": "^2.13.0",
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-echarts": "^4.1.0",
"vue-i18n": "^8.15.3", "vue-i18n": "^8.15.3",
"vue-router": "^3.1.3", "vue-router": "^3.1.3",
"vuex": "^3.1.2", "vuedraggable": "^2.23.2",
"echarts": "^4.6.0", "vuex": "^3.1.2"
"vue-echarts": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "^4.1.0", "@vue/cli-plugin-babel": "^4.1.0",
@ -42,7 +43,7 @@
], ],
"rules": { "rules": {
"vue/no-unused-components": "off", "vue/no-unused-components": "off",
"no-console":"off", "no-console": "off",
"no-unused-vars": "off" "no-unused-vars": "off"
}, },
"parserOptions": { "parserOptions": {

View File

@ -1,19 +1,18 @@
<template> <template>
<el-col v-if="auth"> <el-col v-if="auth">
<el-row id="header-top" type="flex" justify="space-between" align="middle"> <el-row id="header-top" type="flex" justify="space-between" align="middle">
<el-col :span="2">
<el-col :span="12">
<a class="logo"/> <a class="logo"/>
</el-col>
<el-col :span="10">
<ms-top-menus/> <ms-top-menus/>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<ms-user/> <ms-user/>
</el-col> </el-col>
</el-row> </el-row>
<ms-view/> <ms-view/>
<ms-web-socket/>
</el-col> </el-col>
</template> </template>
@ -21,7 +20,6 @@
import MsTopMenus from "./components/common/head/HeaderTopMenus"; import MsTopMenus from "./components/common/head/HeaderTopMenus";
import MsView from "./components/common/router/View"; import MsView from "./components/common/router/View";
import MsUser from "./components/common/head/HeaderUser"; import MsUser from "./components/common/head/HeaderUser";
import MsWebSocket from "./components/common/websocket/WebSocket";
export default { export default {
name: 'app', name: 'app',
@ -33,7 +31,6 @@
beforeCreate() { beforeCreate() {
this.$get("/isLogin").then(response => { this.$get("/isLogin").then(response => {
if (response.data.success) { if (response.data.success) {
window.console.log(response.data);
this.$setLang(response.data.data); this.$setLang(response.data.data);
this.auth = true; this.auth = true;
} else { } else {
@ -43,7 +40,7 @@
window.location.href = "/login" window.location.href = "/login"
}); });
}, },
components: {MsWebSocket, MsUser, MsView, MsTopMenus}, components: {MsUser, MsView, MsTopMenus},
methods: {} methods: {}
} }
</script> </script>
@ -62,6 +59,7 @@
width: 156px; width: 156px;
margin-right: 20px; margin-right: 20px;
display: inline-block; display: inline-block;
line-height: 40px;
background-size: 156px 30px; background-size: 156px 30px;
height: 40px; height: 40px;
background-repeat: no-repeat; background-repeat: no-repeat;
@ -78,6 +76,11 @@
line-height: 40px; line-height: 40px;
} }
.header-top-menus {
display: inline-block;
border: 0;
}
.menus > a { .menus > a {
padding-right: 15px; padding-right: 15px;
text-decoration: none; text-decoration: none;

View File

@ -11,7 +11,15 @@
<el-option v-for="project in projects" :key="project.id" :label="project.name" :value="project.id"/> <el-option v-for="project in projects" :key="project.id" :label="project.name" :value="project.id"/>
</el-select> </el-select>
</el-input> </el-input>
<el-button type="primary" plain :disabled="isDisabled" @click="saveTest">保存</el-button>
<el-button type="primary" plain :disabled="isDisabled" @click="saveTest">
{{$t('commons.save')}}
</el-button>
<el-button type="primary" plain :disabled="isDisabled" @click="runTest">
{{$t('load_test.save_and_run')}}
</el-button>
<el-button type="warning" plain @click="clear">{{$t('commons.cancel')}}</el-button>
</el-row> </el-row>
</el-header> </el-header>
<ms-api-scenario-config :scenarios="test.scenarioDefinition" ref="config"/> <ms-api-scenario-config :scenarios="test.scenarioDefinition" ref="config"/>
@ -41,17 +49,15 @@
} }
}, },
beforeRouteUpdate(to, from, next) {
if (to.params.type === "edit") {
this.getTest(to.query.id);
} else {
this.test = new Test();
this.$refs.config.reset();
}
next();
},
watch: { watch: {
'$route'(to) {
if (to.query.id) {
this.getTest(to.query.id);
} else {
this.test = new Test();
this.$refs.config.reset();
}
},
test: { test: {
handler: function () { handler: function () {
this.change = true; this.change = true;
@ -65,7 +71,7 @@
this.result = this.$get("/api/get/" + id, response => { this.result = this.$get("/api/get/" + id, response => {
let item = response.data; let item = response.data;
this.test.reset({ this.test = new Test({
id: item.id, id: item.id,
projectId: item.projectId, projectId: item.projectId,
name: item.name, name: item.name,
@ -77,20 +83,35 @@
saveTest: function () { saveTest: function () {
this.change = false; this.change = false;
let param = { this.result = this.$post("/api/save", this.getParam(), response => {
id: this.test.id,
projectId: this.test.projectId,
name: this.test.name,
scenarioDefinition: JSON.stringify(this.test.scenarioDefinition)
}
this.result = this.$post("/api/save", param, response => {
this.test.id = response.data; this.test.id = response.data;
this.$message({ this.$message({
message: this.$t('commons.save_success'), message: this.$t('commons.save_success'),
type: 'success' type: 'success'
}); });
}); });
},
runTest: function () {
this.change = false;
this.result = this.$post("/api/run", this.getParam(), response => {
this.test.id = response.data;
this.$message({
message: this.$t('commons.save_success'),
type: 'success'
});
});
},
clear: function () {
this.test = new Test();
},
getParam: function () {
return {
id: this.test.id,
projectId: this.test.projectId,
name: this.test.name,
scenarioDefinition: JSON.stringify(this.test.scenarioDefinition)
}
} }
}, },

View File

@ -3,17 +3,8 @@
<div class="main-content"> <div class="main-content">
<el-card> <el-card>
<template v-slot:header> <template v-slot:header>
<div> <ms-table-header :condition.sync="condition" @search="search" :title="$t('commons.test')"
<el-row type="flex" justify="space-between" align="middle"> @create="create" :createTip="$t('load_test.create')"/>
<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>
</template> </template>
<el-table :data="tableData" class="test-content"> <el-table :data="tableData" class="test-content">
<el-table-column <el-table-column
@ -65,13 +56,14 @@
<script> <script>
import MsTablePagination from "../../common/pagination/TablePagination"; import MsTablePagination from "../../common/pagination/TablePagination";
import MsTableHeader from "../../common/components/MsTableHeader";
export default { export default {
components: {MsTablePagination}, components: {MsTableHeader, MsTablePagination},
data() { data() {
return { return {
result: {}, result: {},
condition: "", condition: {name: ""},
projectId: null, projectId: null,
tableData: [], tableData: [],
multipleSelection: [], multipleSelection: [],
@ -83,10 +75,11 @@
} }
}, },
beforeRouteUpdate(to, from, next) { watch: {
this.projectId = to.params.projectId; '$route'(to) {
this.search(); this.projectId = to.params.projectId;
next(); this.search();
}
}, },
created: function () { created: function () {
@ -95,9 +88,12 @@
}, },
methods: { methods: {
create() {
this.$router.push('/api/test/create');
},
search() { search() {
let param = { let param = {
name: this.condition, name: this.condition.name,
}; };
if (this.projectId !== 'all') { if (this.projectId !== 'all') {
@ -129,7 +125,7 @@
message: this.$t('commons.delete_success'), message: this.$t('commons.delete_success'),
type: 'success' type: 'success'
}); });
this.initTableData(); this.search();
}); });
} }
} }

View File

@ -1,27 +1,5 @@
import {generateId} from "element-ui/src/utils/util"; import {generateId} from "element-ui/src/utils/util";
const assign = function (obj, options) {
if (options) {
for (let name in options) {
if (options.hasOwnProperty(name)) {
if (!(obj[name] instanceof Array)) {
obj[name] = options[name];
}
}
}
}
}
const assigns = function (target, source, type) {
if (target instanceof Array && source instanceof Array) {
if (source && source.length > 0) {
source.forEach((options) => {
target.push(new type(options));
})
}
}
}
export const BODY_TYPE = { export const BODY_TYPE = {
KV: "KV", KV: "KV",
TEXT: "TEXT" TEXT: "TEXT"
@ -33,54 +11,80 @@ export const ASSERTION_TYPE = {
RESPONSE_TIME: "RESPONSE_TIME" RESPONSE_TIME: "RESPONSE_TIME"
} }
export class Test { class BaseConfig {
constructor(options) {
this.reset(options); set(options) {
options = this.initOptions(options)
for (let name in options) {
if (options.hasOwnProperty(name)) {
if (!(this[name] instanceof Array)) {
this[name] = options[name];
}
}
}
} }
reset(options) { sets(types, options) {
options = this.getDefaultOptions(options); options = this.initOptions(options)
if (types) {
for (let name in types) {
if (types.hasOwnProperty(name) && options.hasOwnProperty(name)) {
options[name].forEach((o) => {
this[name].push(new types[name](o));
})
}
}
}
}
initOptions(options) {
return options || {};
}
}
export class Test extends BaseConfig {
constructor(options) {
super();
this.id = null; this.id = null;
this.name = null; this.name = null;
this.projectId = null; this.projectId = null;
this.scenarioDefinition = []; this.scenarioDefinition = [];
assign(this, options); this.set(options);
assigns(this.scenarioDefinition, options.scenarioDefinition, Scenario); this.sets({scenarioDefinition: Scenario}, options);
} }
getDefaultOptions(options) { initOptions(options) {
options = options || {}; options = options || {};
options.scenarioDefinition = options.scenarioDefinition || [new Scenario()]; options.scenarioDefinition = options.scenarioDefinition || [new Scenario()];
return options; return options;
} }
} }
export class Scenario { export class Scenario extends BaseConfig {
constructor(options) { constructor(options) {
options = this.getDefaultOptions(options); super();
this.name = null; this.name = null;
this.url = null; this.url = null;
this.variables = []; this.variables = [];
this.headers = []; this.headers = [];
this.requests = []; this.requests = [];
assign(this, options); this.set(options);
assigns(this.variables, options.variables, KeyValue); this.sets({variables: KeyValue, headers: KeyValue, requests: Request}, options);
assigns(this.headers, options.headers, KeyValue);
assigns(this.requests, options.requests, Request);
} }
getDefaultOptions(options) { initOptions(options) {
options = options || {}; options = options || {};
options.requests = options.requests || [new Request()]; options.requests = options.requests || [new Request()];
return options; return options;
} }
} }
export class Request { export class Request extends BaseConfig {
constructor(options) { constructor(options) {
options = this.getDefaultOptions(options); super();
this.randomId = generateId(); this.randomId = generateId();
this.name = null; this.name = null;
this.url = null; this.url = null;
@ -91,13 +95,12 @@ export class Request {
this.assertions = null; this.assertions = null;
this.extract = []; this.extract = [];
assign(this, options); this.set(options);
assigns(this.parameters, options.parameters, KeyValue); this.sets({parameters: KeyValue, headers: KeyValue}, options);
assigns(this.headers, options.headers, KeyValue);
// TODO assigns extract // TODO assigns extract
} }
getDefaultOptions(options) { initOptions(options) {
options = options || {}; options = options || {};
options.method = "GET"; options.method = "GET";
options.body = new Body(options.body); options.body = new Body(options.body);
@ -106,15 +109,15 @@ export class Request {
} }
} }
export class Body { export class Body extends BaseConfig {
constructor(options) { constructor(options) {
options = options || {}; super();
this.type = null; this.type = null;
this.text = null; this.text = null;
this.kvs = []; this.kvs = [];
assign(this, options); this.set(options);
assigns(this.kvs, options.kvs, KeyValue); this.sets({kvs: KeyValue}, options);
} }
isKV() { isKV() {
@ -122,72 +125,69 @@ export class Body {
} }
} }
export class KeyValue { export class KeyValue extends BaseConfig {
constructor(options) { constructor(options) {
options = options || {}; super();
this.key = null; this.key = null;
this.value = null; this.value = null;
assign(this, options); this.set(options);
} }
} }
export class Assertions { export class Assertions extends BaseConfig {
constructor(options) { constructor(options) {
options = this.getDefaultOptions(options); super();
this.text = []; this.text = [];
this.regex = []; this.regex = [];
this.responseTime = null; this.responseTime = null;
assign(this, options); this.set(options);
assigns(this.text, options.text, KeyValue); this.sets({text: KeyValue, regex: KeyValue}, options);
assigns(this.regex, options.regex, KeyValue);
} }
getDefaultOptions(options) { initOptions(options) {
options = options || {}; options = options || {};
options.responseTime = new ResponseTime(options.responseTime); options.responseTime = new ResponseTime(options.responseTime);
return options; return options;
} }
} }
class AssertionType { class AssertionType extends BaseConfig {
constructor(type) { constructor(type) {
super();
this.type = type; this.type = type;
} }
} }
export class Text extends AssertionType { export class Text extends AssertionType {
constructor(options) { constructor(options) {
options = options || {};
super(ASSERTION_TYPE.TEXT); super(ASSERTION_TYPE.TEXT);
this.subject = null; this.subject = null;
this.condition = null; this.condition = null;
this.value = null; this.value = null;
assign(this, options); this.set(options);
} }
} }
export class Regex extends AssertionType { export class Regex extends AssertionType {
constructor(options) { constructor(options) {
options = options || {};
super(ASSERTION_TYPE.REGEX); super(ASSERTION_TYPE.REGEX);
this.subject = null; this.subject = null;
this.expression = null; this.expression = null;
this.description = null; this.description = null;
assign(this, options); this.set(options);
} }
} }
export class ResponseTime extends AssertionType { export class ResponseTime extends AssertionType {
constructor(options) { constructor(options) {
options = options || {};
super(ASSERTION_TYPE.RESPONSE_TIME); super(ASSERTION_TYPE.RESPONSE_TIME);
this.responseInTime = null; this.responseInTime = null;
assign(this, options); this.set(options);
} }
} }

View File

@ -0,0 +1,35 @@
<template>
<span>
<ms-table-operator-button icon="el-icon-edit"
@click="editClick" @click.stop="editClickStop"/>
<ms-table-operator-button icon="el-icon-delete" type="danger"
@click="deletClick" @click.stop="deleteClickStop"/>
</span>
</template>
<script>
import MsTableOperatorButton from "./MsTableOperatorButton";
export default {
name: "MsTableOperator",
components: {MsTableOperatorButton},
methods: {
editClick() {
this.$emit('editClick');
},
editClickStop() {
this.$emit('editClickStop');
},
deletClick() {
this.$emit('deleteClick');
},
deleteClickStop() {
this.$emit('deleteClickStop');
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,34 @@
<template>
<el-button @click="click"
@click.stop="clickStop" :type="type"
:icon="icon" size="mini" circle/>
</template>
<script>
import MsTableButton from "./MsTableButton";
export default {
name: "MsTableOperatorButton",
components: {MsTableButton},
props: {
icon: {
type: String,
default: 'el-icon-question'
},
type: {
type: String,
default: 'primary'
}
},
methods: {
click() {
this.$emit('click');
},
clickStop() {
this.$emit('clickStop');
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,11 +1,11 @@
<template> <template>
<div> <div v-loading="result.loading">
<div class="recent-text"> <div class="recent-text">
<i class="el-icon-time"/> <i class="el-icon-time"/>
<span>{{options.title}}</span> <span>{{options.title}}</span>
<i class="el-icon-refresh" @click="recent"/>
</div> </div>
<el-menu-item :key="i.id" v-for="i in items" <el-menu-item :key="i.id" v-for="i in items" :index="getIndex(i)" :route="getRouter(i)">
:index="getIndex(i)" :route="getRouter(i)">
<span class="title">{{ i.name }}</span> <span class="title">{{ i.name }}</span>
</el-menu-item> </el-menu-item>
</div> </div>
@ -21,14 +21,11 @@
options: Object options: Object
}, },
mounted() { mounted() {
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) { this.recent();
this.$get(this.options.url, (response) => {
this.items = response.data;
});
}
}, },
data() { data() {
return { return {
result: {},
items: [] items: []
} }
}, },
@ -45,6 +42,16 @@
} }
} }
} }
},
methods: {
recent: function () {
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
this.result = this.$get(this.options.url, (response) => {
this.items = response.data;
});
}
}
} }
} }
</script> </script>
@ -60,6 +67,17 @@
.recent-text span { .recent-text span {
padding-left: 6px; padding-left: 6px;
line-height: 36px;
}
.recent-text .el-icon-refresh {
cursor: pointer;
float: right;
line-height: 36px;
}
.recent-text .el-icon-refresh:hover {
color: #BBBBBB;
} }
.title { .title {

View File

@ -26,7 +26,7 @@ import PerformanceReportView from "../../performance/report/PerformanceReportVie
import ApiReportView from "../../api/report/ApiReportView"; import ApiReportView from "../../api/report/ApiReportView";
import TrackHome from "../../track/home/TrackHome"; import TrackHome from "../../track/home/TrackHome";
import TestPlan from "../../track/plan/TestPlan"; import TestPlan from "../../track/plan/TestPlan";
import TestPlanView from "../../track/plan/TestPlanView"; import TestPlanView from "../../track/plan/view/TestPlanView";
import TestCase from "../../track/case/TestCase"; import TestCase from "../../track/case/TestCase";
import TestTrack from "../../track/TestTrack"; import TestTrack from "../../track/TestTrack";

View File

@ -12,8 +12,7 @@
<el-table-column prop="workspaceName" label="所属工作空间"/> <el-table-column prop="workspaceName" label="所属工作空间"/>
<el-table-column> <el-table-column>
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-button @click="edit(scope.row)" type="primary" icon="el-icon-edit" size="mini" circle/> <ms-table-operator @editClick="edit(scope.row)" @deleteClick="del(scope.row)"/>
<el-button @click="del(scope.row)" type="danger" icon="el-icon-delete" size="mini" circle/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -48,10 +47,11 @@
import {TokenKey} from "../../../common/js/constants"; import {TokenKey} from "../../../common/js/constants";
import MsTablePagination from "../common/pagination/TablePagination"; import MsTablePagination from "../common/pagination/TablePagination";
import MsTableHeader from "../common/components/MsTableHeader"; import MsTableHeader from "../common/components/MsTableHeader";
import MsTableOperator from "../common/components/MsTableOperator";
export default { export default {
name: "MsProject", name: "MsProject",
components: {MsCreateBox, MsTablePagination, MsTableHeader}, components: {MsTableOperator, MsCreateBox, MsTablePagination, MsTableHeader},
data() { data() {
return { return {
createVisible: false, createVisible: false,

View File

@ -46,19 +46,10 @@
<!-- dialog of workspace member --> <!-- dialog of workspace member -->
<el-dialog :visible.sync="memberVisible" width="70%" :destroy-on-close="true" @close="closeMemberFunc"> <el-dialog :visible.sync="memberVisible" width="70%" :destroy-on-close="true" @close="closeMemberFunc">
<el-row type="flex" justify="space-between" align="middle"> <ms-table-header :condition.sync="dialogCondition" @create="addMember"
<span class="member-title">{{$t('commons.member')}} :create-tip="dialogBtnTips" :title="$t('commons.member')"/>
<ms-create-box :tips="addTips" :exec="addMember" v-permission="['admin','org_admin']"/>
</span>
<span class="search">
<el-input type="text" size="small"
:placeholder="$t('organization.search_by_name')"
prefix-icon="el-icon-search"
maxlength="60" v-model="condition.name" clearable/>
</span>
</el-row>
<!-- organization member table --> <!-- organization member table -->
<el-table :data="memberLineData" style="width: 100%"> <el-table :data="memberLineData" style="width: 100%;margin-top: 5px;">
<el-table-column prop="name" :label="$t('commons.username')"/> <el-table-column prop="name" :label="$t('commons.username')"/>
<el-table-column prop="email" :label="$t('commons.email')"/> <el-table-column prop="email" :label="$t('commons.email')"/>
<el-table-column prop="phone" :label="$t('commons.phone')"/> <el-table-column prop="phone" :label="$t('commons.phone')"/>
@ -394,9 +385,11 @@
result: {}, result: {},
loading: false, loading: false,
createVisible: false, createVisible: false,
btnTips: this.$t('workspace.add'), btnTips: this.$t('workspace.create'),
dialogBtnTips: this.$t('member.create'),
addTips: this.$t('member.create'), addTips: this.$t('member.create'),
condition: {}, condition: {},
dialogCondition: {},
items: [], items: [],
currentPage: 1, currentPage: 1,
pageSize: 5, pageSize: 5,

View File

@ -31,19 +31,10 @@
</el-card> </el-card>
<!-- dialog of organization member --> <!-- dialog of organization member -->
<el-dialog :visible.sync="memberVisible" width="70%" :destroy-on-close="true" @close="closeMemberFunc"> <el-dialog :visible.sync="memberVisible" width="70%" :destroy-on-close="true" @close="closeMemberFunc">
<el-row type="flex" justify="space-between" align="middle"> <ms-table-header :condition.sync="dialogCondition" @create="addMember"
<span class="member-title">{{$t('commons.member')}} :create-tip="dialogBtnTips" :title="$t('commons.member')"/>
<ms-create-box :tips="btnTips" :exec="addMember"/>
</span>
<span class="search">
<el-input type="text" size="small"
:placeholder="$t('organization.search_by_name')"
prefix-icon="el-icon-search"
maxlength="60" v-model="condition.name" clearable/>
</span>
</el-row>
<!-- organization member table --> <!-- organization member table -->
<el-table :data="memberLineData" style="width: 100%"> <el-table :data="memberLineData" style="width: 100%;margin-top:5px;">
<el-table-column prop="name" :label="$t('commons.username')"/> <el-table-column prop="name" :label="$t('commons.username')"/>
<el-table-column prop="email" :label="$t('commons.email')"/> <el-table-column prop="email" :label="$t('commons.email')"/>
<el-table-column prop="phone" :label="$t('commons.phone')"/> <el-table-column prop="phone" :label="$t('commons.phone')"/>
@ -214,8 +205,10 @@
pageMemberSize: 5, pageMemberSize: 5,
memberTotal: 0, memberTotal: 0,
currentRow: {}, currentRow: {},
btnTips: this.$t('member.create'), btnTips: this.$t('organization.create'),
dialogBtnTips: this.$t('member.create'),
condition: {}, condition: {},
dialogCondition: {},
tableData: [], tableData: [],
memberLineData: [], memberLineData: [],
form: {}, form: {},

View File

@ -87,19 +87,10 @@
<!-- dialog of workspace member --> <!-- dialog of workspace member -->
<el-dialog :visible.sync="memberVisible" width="70%" :destroy-on-close="true" @close="closeMemberFunc"> <el-dialog :visible.sync="memberVisible" width="70%" :destroy-on-close="true" @close="closeMemberFunc">
<el-row type="flex" justify="space-between" align="middle"> <ms-table-header :condition.sync="dialogCondition" @create="addMember"
<span class="member-title">{{$t('commons.member')}} :create-tip="dialogBtnTips" :title="$t('commons.member')"/>
<ms-create-box :tips="addTips" :exec="addMember"/>
</span>
<span class="search">
<el-input type="text" size="small"
:placeholder="$t('organization.search_by_name')"
prefix-icon="el-icon-search"
maxlength="60" v-model="condition.name" clearable/>
</span>
</el-row>
<!-- organization member table --> <!-- organization member table -->
<el-table :data="memberLineData" style="width: 100%"> <el-table :data="memberLineData" style="width: 100%;margin-top: 5px;">
<el-table-column prop="name" :label="$t('commons.username')"/> <el-table-column prop="name" :label="$t('commons.username')"/>
<el-table-column prop="email" :label="$t('commons.email')"/> <el-table-column prop="email" :label="$t('commons.email')"/>
<el-table-column prop="phone" :label="$t('commons.phone')"/> <el-table-column prop="phone" :label="$t('commons.phone')"/>
@ -437,9 +428,11 @@
memberVisible: false, memberVisible: false,
addMemberVisible: false, addMemberVisible: false,
updateMemberVisible: false, updateMemberVisible: false,
btnTips: this.$t('workspace.add'), btnTips: this.$t('workspace.create'),
dialogBtnTips: this.$t('member.create'),
addTips: this.$t('member.create'), addTips: this.$t('member.create'),
condition: {}, condition: {},
dialogCondition: {},
items: [], items: [],
currentPage: 1, currentPage: 1,
pageSize: 5, pageSize: 5,

View File

@ -112,7 +112,7 @@
return { return {
result: {}, result: {},
form: {}, form: {},
btnTips: "添加工作空间成员", btnTips: this.$t('member.create'),
createVisible: false, createVisible: false,
updateVisible: false, updateVisible: false,
queryPath: "/user/ws/member/list", queryPath: "/user/ws/member/list",

View File

@ -1,4 +1,4 @@
<template> <template xmlns:v-slot="http://www.w3.org/1999/XSL/Transform">
<div> <div>
<el-card v-loading="result.loading"> <el-card v-loading="result.loading">
@ -27,26 +27,32 @@
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="priority" prop="priority"
:filters="priorityFilters"
:filter-method="filter"
:label="$t('test_track.case.priority')" :label="$t('test_track.case.priority')"
show-overflow-tooltip> show-overflow-tooltip>
<template v-slot:default="scope">
<priority-table-item :value="scope.row.priority"/>
</template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="type" prop="type"
:filters="typeFilters"
:filter-method="filter"
:label="$t('test_track.case.type')" :label="$t('test_track.case.type')"
show-overflow-tooltip> show-overflow-tooltip>
<template v-slot:default="scope"> <template v-slot:default="scope">
<span v-if="scope.row.type == 'functional'">{{$t('test_track.case.functional_test')}}</span> <type-table-item :value="scope.row.type"/>
<span v-if="scope.row.type == 'performance'">{{$t('commons.performance')}}</span>
<span v-if="scope.row.type == 'api'">{{$t('commons.api')}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="method" prop="method"
:filters="methodFilters"
:filter-method="filter"
:label="$t('test_track.case.method')" :label="$t('test_track.case.method')"
show-overflow-tooltip> show-overflow-tooltip>
<template v-slot:default="scope"> <template v-slot:default="scope">
<span v-if="scope.row.method == 'manual'">{{$t('test_track.case.manual')}}</span> <method-table-item :value="scope.row.method"/>
<span v-if="scope.row.method == 'auto'">{{$t('test_track.case.auto')}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -55,12 +61,16 @@
show-overflow-tooltip> show-overflow-tooltip>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="createTime"
sortable
:label="$t('commons.create_time')"> :label="$t('commons.create_time')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{ scope.row.createTime | timestampFormatDate }}</span> <span>{{ scope.row.createTime | timestampFormatDate }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="updateTime"
sortable
:label="$t('commons.update_time')"> :label="$t('commons.update_time')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span> <span>{{ scope.row.updateTime | timestampFormatDate }}</span>
@ -69,8 +79,7 @@
<el-table-column <el-table-column
:label="$t('commons.operating')"> :label="$t('commons.operating')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-button @click="handleEdit(scope.row)" type="primary" icon="el-icon-edit" size="mini" circle/> <ms-table-operator @editClick="handleEdit(scope.row)" @deleteClick="handleDelete(scope.row)"/>
<el-button @click="handleDelete(scope.row)" type="danger" icon="el-icon-delete" size="mini" circle/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -90,20 +99,43 @@
import MsTablePagination from '../../../../components/common/pagination/TablePagination'; import MsTablePagination from '../../../../components/common/pagination/TablePagination';
import NodeBreadcrumb from '../../common/NodeBreadcrumb'; import NodeBreadcrumb from '../../common/NodeBreadcrumb';
import MsTableHeader from '../../../../components/common/components/MsTableHeader'; import MsTableHeader from '../../../../components/common/components/MsTableHeader';
import PriorityTableItem from "../../common/TableItems/PriorityTableItem";
import TypeTableItem from "../../common/TableItems/TypeTableItem";
import MethodTableItem from "../../common/TableItems/MethodTableItem";
import MsTableOperator from "../../../common/components/MsTableOperator";
export default { export default {
name: "TestCaseList", name: "TestCaseList",
components: {MsCreateBox, TestCaseImport, TestCaseExport, MsTablePagination, NodeBreadcrumb, MsTableHeader}, components: {
data() { MsTableOperator,
return { MethodTableItem,
result: {}, TypeTableItem,
deletePath: "/test/case/delete", PriorityTableItem,
condition: {}, MsCreateBox, TestCaseImport, TestCaseExport, MsTablePagination, NodeBreadcrumb, MsTableHeader},
tableData: [], data() {
currentPage: 1, return {
pageSize: 5, result: {},
total: 0, deletePath: "/test/case/delete",
} condition: {},
tableData: [],
currentPage: 1,
pageSize: 5,
total: 0,
priorityFilters: [
{text: 'P0', value: 'P0'},
{text: 'P1', value: 'P1'},
{text: 'P2', value: 'P2'}
],
methodFilters: [
{text: this.$t('test_track.case.manual'), value: 'manual'},
{text: this.$t('test_track.case.auto'), value: 'auto'}
],
typeFilters: [
{text: this.$t('commons.functional'), value: 'functional'},
{text: this.$t('commons.performance'), value: 'performance'},
{text: this.$t('commons.api'), value: 'api'}
]
}
}, },
props: { props: {
currentProject: { currentProject: {
@ -174,6 +206,10 @@
refresh() { refresh() {
this.condition = {}; this.condition = {};
this.$emit('refresh'); this.$emit('refresh');
},
filter(value, row, column) {
const property = column['property'];
return row[property] === value;
} }
} }
} }

View File

@ -1,183 +0,0 @@
<template>
<div>
<el-input :placeholder="$t('test_track.module.search')" v-model="filterText" size="small"></el-input>
<el-tree
v-loading="result.loading"
class="filter-tree node-tree"
:data="treeNodes"
node-key="id"
@node-drag-end="handleDragEnd"
:filter-node-method="filterNode"
:expand-on-click-node="false"
highlight-current
draggable
ref="tree">
<template v-slot:default="{node}">
<span class="custom-tree-node" @click="selectNode(node)">
{{node.label}}
</span>
</template>
</el-tree>
</div>
</template>
<script>
export default {
name: "PlanNodeTree",
data() {
return {
result: {},
filterText: '',
defaultProps: {
children: 'children',
label: 'label'
},
dialogTableVisible: false,
defaultKeys: [],
treeNodes: []
};
},
props: {
planId: {
type: String
},
showAll: {
type: Boolean
}
},
created() {
this.initTree();
},
watch: {
filterText(val) {
this.$refs.tree.filter(val);
},
planId() {
this.initTree();
},
'$route'(to, from) {
if (to.path.indexOf("/track/plan/view/") >= 0){
this.initTree();
}
}
},
selectNode(node) {
let nodeIds = [];
this.getChildNodeId(node, nodeIds);
this.$emit("nodeSelectEvent", nodeIds);
},
getChildNodeId(rootNode, nodeIds) {
//ID
nodeIds.push(rootNode.data.id);
for (let i = 0; i < rootNode.childNodes.length; i++) {
this.getChildNodeId(rootNode.childNodes[i], nodeIds);
}
return nodeIds;
},
methods: {
initTree() {
if (this.showAll) {
this.getAllNodeTreeByPlanId();
} else {
this.getNodeTreeByPlanId();
}
},
handleDragEnd(draggingNode, dropNode, dropType, ev) {
let param = {};
param.id = draggingNode.data.id;
if(dropType === 'inner'){
param.pId = dropNode.data.id;
param.level = dropNode.data.level + 1;
} else {
if(dropNode.parent.id === 0){
param.pId = 0;
param.level = 1;
} else {
param.pId = dropNode.parent.data.id;
param.level = dropNode.parent.data.level + 1;
}
}
this.$post('/case/node/edit', param);
},
selectNode(node) {
let nodeIds = [];
let nodeNames = [];
this.getChildNodeId(node, nodeIds);
this.getParentNodeName(node, nodeNames);
this.$emit("nodeSelectEvent", nodeIds, nodeNames);
},
getChildNodeId(rootNode, nodeIds) {
//ID
nodeIds.push(rootNode.data.id);
for (let i = 0; i < rootNode.childNodes.length; i++){
this.getChildNodeId(rootNode.childNodes[i], nodeIds);
}
},
getParentNodeName(rootNode, nodeNames) {
if (rootNode.parent && rootNode.parent.id != 0) {
this.getParentNodeName(rootNode.parent, nodeNames)
}
if (rootNode.data.name && rootNode.data.name != '') {
nodeNames.push(rootNode.data.name);
}
},
filterNode(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
getNodeTreeByPlanId() {
if(this.planId){
this.result = this.$get("/case/node/list/plan/" + this.planId, response => {
this.treeNodes = response.data;
});
}
},
getAllNodeTreeByPlanId() {
if (this.planId) {
this.result = this.$get("/case/node/list/all/plan/" + this.planId, response => {
this.treeNodes = response.data;
});
}
}
}
}
</script>
<style scoped>
.el-dropdown-link {
cursor: pointer;
color: #409EFF;
}
.el-icon-arrow-down {
font-size: 12px;
}
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
width: 100%;
}
.node-tree {
margin-top: 15px;
}
.father .child {
display: none;
}
.father:hover .child {
display: block;
}
</style>

View File

@ -0,0 +1,21 @@
<template>
<div>
<span v-if="value == 'manual'">{{$t('test_track.case.manual')}}</span>
<span v-if="value == 'auto'">{{$t('test_track.case.auto')}}</span>
</div>
</template>
<script>
export default {
name: "MethodTableItem",
props: {
value: {
type: String
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,36 @@
<template>
<div>
<el-tag v-if="value == 'P0'"
type="danger"
effect="dark"
size="mini">{{value}}</el-tag>
<el-tag v-if="value == 'P1'"
type="danger"
effect="light"
size="mini">{{value}}</el-tag>
<el-tag v-if="value == 'P2'"
type="warning"
effect="dark"
size="mini">{{value}}</el-tag>
<el-tag v-if="value == 'P3'"
type="warning"
effect="light"
size="mini">{{value}}</el-tag>
</div>
</template>
<script>
export default {
name: "PriorityTableItem",
props: {
value: {
type: String
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,39 @@
<template>
<div>
<el-tag v-if="value == 'Prepare'"
type="info"
effect="dark"
size="mini">{{$t('test_track.plan.plan_status_prepare')}}</el-tag>
<el-tag v-if="value == 'Pass'"
type="success"
effect="dark"
size="mini">{{$t('test_track.plan_view.pass')}}</el-tag>
<el-tag v-if="value == 'Failure'"
type="danger"
effect="dark"
size="mini">{{$t('test_track.plan_view.failure')}}</el-tag>
<el-tag v-if="value == 'Blocking'"
type="warning"
effect="dark"
size="mini">{{$t('test_track.plan_view.blocking')}}</el-tag>
<el-tag v-if="value == 'Skip'"
type="info"
effect="dark"
size="mini">{{$t('test_track.plan_view.skip')}}</el-tag>
</div>
</template>
<script>
export default {
name: "StatusTableItem",
props: {
value: {
type: String
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,24 @@
<template>
<div>
<span v-if="value == 'functional'">{{$t('commons.functional')}}</span>
<span v-if="value == 'performance'">{{$t('commons.performance')}}</span>
<span v-if="value == 'api'">{{$t('commons.api')}}</span>
</div>
</template>
<script>
export default {
name: "TypeTableItem",
props: {
value: {
type: String
}
}
}
</script>
<style scoped>
</style>

View File

@ -43,6 +43,7 @@
this.$refs.testPlanEditDialog.openTestPlanEditDialog(data); this.$refs.testPlanEditDialog.openTestPlanEditDialog(data);
}, },
refreshTestPlanList() { refreshTestPlanList() {
this.$refs.testPlanList.condition = {};
this.$refs.testPlanList.initTableData(); this.$refs.testPlanList.initTableData();
} }
} }

View File

@ -4,23 +4,8 @@
<el-main class="main-content"> <el-main class="main-content">
<el-card v-loading="result.loading"> <el-card v-loading="result.loading">
<template v-slot:header> <template v-slot:header>
<div> <ms-table-header :condition.sync="condition" @search="initTableData" @create="testPlanCreate"
<el-row type="flex" justify="space-between" align="middle"> :create-tip="$t('test_track.plan.create_plan')" :title="$t('test_track.plan.test_plan')"/>
<el-col :span="5">
<span class="title">{{$t('test_track.plan.test_plan')}}</span>
<ms-create-box :tips="$t('test_track.plan.create_plan')" :exec="testPlanCreate"/>
</el-col>
<el-col :span="5">
<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="initTableData" clearable/>
</span>
</el-col>
</el-row>
</div>
</template> </template>
<el-table <el-table
@ -78,12 +63,7 @@
<el-table-column <el-table-column
:label="$t('commons.operating')"> :label="$t('commons.operating')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-button @click="handleEdit(scope.row)" <ms-table-operator @editClick="handleEdit(scope.row)" @deleteClick="handleDelete(scope.row)"/>
@click.stop="deleteVisible = true" type="primary"
icon="el-icon-edit" size="mini" circle/>
<el-button @click="handleDelete(scope.row)"
@click.stop="deleteVisible = true" type="danger"
icon="el-icon-delete" size="mini" circle/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -99,16 +79,20 @@
<script> <script>
import MsCreateBox from '../../../settings/CreateBox'; import MsCreateBox from '../../../settings/CreateBox';
import MsTablePagination from '../../../../components/common/pagination/TablePagination'; import MsTablePagination from '../../../../components/common/pagination/TablePagination';
import MsTableHeader from "../../../common/components/MsTableHeader";
import MsDialogFooter from "../../../common/components/MsDialogFooter";
import MsTableOperatorButton from "../../../common/components/MsTableOperatorButton";
import MsTableOperator from "../../../common/components/MsTableOperator";
export default { export default {
name: "TestPlanList", name: "TestPlanList",
components: {MsCreateBox, MsTablePagination}, components: {MsTableOperator, MsTableOperatorButton, MsDialogFooter, MsTableHeader, MsCreateBox, MsTablePagination},
data() { data() {
return { return {
result: {}, result: {},
queryPath: "/test/plan/list", queryPath: "/test/plan/list",
deletePath: "/test/plan/delete", deletePath: "/test/plan/delete",
condition: "", condition: {},
currentPage: 1, currentPage: 1,
pageSize: 5, pageSize: 5,
total: 0, total: 0,
@ -121,10 +105,7 @@
}, },
methods: { methods: {
initTableData() { initTableData() {
let param = { this.result = this.$post(this.buildPagePath(this.queryPath), this.condition, response => {
name: this.condition,
};
this.result = this.$post(this.buildPagePath(this.queryPath), param, response => {
let data = response.data; let data = response.data;
this.total = data.itemCount; this.total = data.itemCount;
this.tableData = data.listObject; this.tableData = data.listObject;

View File

@ -37,10 +37,10 @@
<script> <script>
import NodeTree from "../common/NodeTree"; import NodeTree from "../../common/NodeTree";
import TestPlanTestCaseList from "./components/TestPlanTestCaseList"; import TestPlanTestCaseList from "./comonents/TestPlanTestCaseList";
import TestCaseRelevance from "./components/TestCaseRelevance"; import TestCaseRelevance from "./comonents/TestCaseRelevance";
import SelectMenu from "../common/SelectMenu"; import SelectMenu from "../../common/SelectMenu";
export default { export default {
name: "TestPlanView", name: "TestPlanView",

View File

@ -20,8 +20,8 @@
</template> </template>
<script> <script>
import {WORKSPACE_ID} from '../../../../../common/js/constants' import {WORKSPACE_ID} from '../../../../../../common/js/constants'
import MsDialogFooter from '../../../common/components/MsDialogFooter' import MsDialogFooter from '../../../../common/components/MsDialogFooter'
export default { export default {
name: "executorEdit", name: "executorEdit",

View File

@ -19,8 +19,8 @@
</template> </template>
<script> <script>
import TestPlanTestCaseStatusButton from '../common/TestPlanTestCaseStatusButton'; import TestPlanTestCaseStatusButton from '../../common/TestPlanTestCaseStatusButton';
import MsDialogFooter from '../../../common/components/MsDialogFooter' import MsDialogFooter from '../../../../common/components/MsDialogFooter'
export default { export default {
name: "statusEdit", name: "statusEdit",

View File

@ -54,8 +54,8 @@
<script> <script>
import NodeTree from '../../common/NodeTree'; import NodeTree from '../../../common/NodeTree';
import MsDialogFooter from '../../../common/components/MsDialogFooter' import MsDialogFooter from '../../../../common/components/MsDialogFooter'
export default { export default {
name: "TestCaseRelevance", name: "TestCaseRelevance",

View File

@ -165,7 +165,7 @@
</template> </template>
<script> <script>
import TestPlanTestCaseStatusButton from '../common/TestPlanTestCaseStatusButton'; import TestPlanTestCaseStatusButton from '../../common/TestPlanTestCaseStatusButton';
export default { export default {
name: "TestPlanTestCaseEdit", name: "TestPlanTestCaseEdit",

View File

@ -33,49 +33,36 @@
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="priority" prop="priority"
:filters="priorityFilters"
:filter-method="filter"
:label="$t('test_track.case.priority')"> :label="$t('test_track.case.priority')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-tag v-if="scope.row.priority == 'P0'" <priority-table-item :value="scope.row.priority" ref="priority"/>
type="danger"
effect="dark"
size="mini">{{scope.row.priority}}</el-tag>
<el-tag v-if="scope.row.priority == 'P1'"
type="danger"
effect="light"
size="mini">{{scope.row.priority}}</el-tag>
<el-tag v-if="scope.row.priority == 'P2'"
type="warning"
effect="dark"
size="mini">{{scope.row.priority}}</el-tag>
<el-tag v-if="scope.row.priority == 'P3'"
type="warning"
effect="light"
size="mini">{{scope.row.priority}}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="type" prop="type"
:filters="typeFilters"
:filter-method="filter"
:label="$t('test_track.case.type')" :label="$t('test_track.case.type')"
show-overflow-tooltip> show-overflow-tooltip>
<template v-slot:default="scope"> <template v-slot:default="scope">
<span v-if="scope.row.type == 'functional'">{{$t('commons.functional')}}</span> <type-table-item :value="scope.row.type"/>
<span v-if="scope.row.type == 'performance'">{{$t('commons.performance')}}</span>
<span v-if="scope.row.type == 'api'">{{$t('commons.api')}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="method" prop="method"
:filters="methodFilters"
:filter-method="filter"
:label="$t('test_track.case.method')" :label="$t('test_track.case.method')"
show-overflow-tooltip> show-overflow-tooltip>
<template v-slot:default="scope"> <template v-slot:default="scope">
<span v-if="scope.row.method == 'manual'">{{$t('test_track.case.manual')}}</span> <method-table-item :value="scope.row.method"/>
<span v-if="scope.row.method == 'auto'">{{$t('test_track.case.auto')}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
prop="executor" prop="executor"
:label="$t('test_track.plan_view.executor')"> :label="$t('test_track.plan_view.executor')">
@ -83,32 +70,17 @@
<el-table-column <el-table-column
prop="status" prop="status"
:filters="statusFilters"
:filter-method="filter"
:label="$t('test_track.plan_view.execute_result')"> :label="$t('test_track.plan_view.execute_result')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-tag v-if="scope.row.status == 'Prepare'" <status-table-item :value="scope.row.status"/>
type="info"
effect="dark"
size="mini">{{$t('test_track.plan.plan_status_prepare')}}</el-tag>
<el-tag v-if="scope.row.status == 'Pass'"
type="success"
effect="dark"
size="mini">{{$t('test_track.plan_view.pass')}}</el-tag>
<el-tag v-if="scope.row.status == 'Failure'"
type="danger"
effect="dark"
size="mini">{{$t('test_track.plan_view.failure')}}</el-tag>
<el-tag v-if="scope.row.status == 'Blocking'"
type="warning"
effect="dark"
size="mini">{{$t('test_track.plan_view.blocking')}}</el-tag>
<el-tag v-if="scope.row.status == 'Skip'"
type="info"
effect="dark"
size="mini">{{$t('test_track.plan_view.skip')}}</el-tag>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
sortable
prop="updateTime"
:label="$t('commons.update_time')"> :label="$t('commons.update_time')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span> <span>{{ scope.row.updateTime | timestampFormatDate }}</span>
@ -117,8 +89,7 @@
<el-table-column <el-table-column
:label="$t('commons.operating')"> :label="$t('commons.operating')">
<template v-slot:default="scope"> <template v-slot:default="scope">
<el-button @click="handleEdit(scope.row, scope.$index)" type="primary" icon="el-icon-edit" size="mini" circle/> <ms-table-operator @editClick="handleEdit(scope.row, scope.$index)" @deleteClick="handleDelete(scope.row)"/>
<el-button @click="handleDelete(scope.row)" type="danger" icon="el-icon-unlock" size="mini" circle/>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -135,21 +106,31 @@
</template> </template>
<script> <script>
import PlanNodeTree from '../../common/PlanNodeTree';
import ExecutorEdit from './ExecutorEdit'; import ExecutorEdit from './ExecutorEdit';
import StatusEdit from './StatusEdit'; import StatusEdit from './StatusEdit';
import TestPlanTestCaseEdit from "../components/TestPlanTestCaseEdit"; import TestPlanTestCaseEdit from "./TestPlanTestCaseEdit";
import MsTipButton from '../../../../components/common/components/MsTipButton'; import MsTipButton from '../../../../common/components/MsTipButton';
import MsTablePagination from '../../../../components/common/pagination/TablePagination'; import MsTablePagination from '../../../../common/pagination/TablePagination';
import MsTableHeader from '../../../../components/common/components/MsTableHeader'; import MsTableHeader from '../../../../common/components/MsTableHeader';
import MsTableButton from '../../../../components/common/components/MsTableButton'; import MsTableButton from '../../../../common/components/MsTableButton';
import NodeBreadcrumb from '../../common/NodeBreadcrumb'; import NodeBreadcrumb from '../../../common/NodeBreadcrumb';
import {TokenKey} from '../../../../../common/js/constants'; import {TokenKey} from '../../../../../../common/js/constants';
import {tableFilter} from '../../../../../../common/js/utils';
import PriorityTableItem from "../../../common/TableItems/PriorityTableItem";
import StatusTableItem from "../../../common/TableItems/StatusTableItem";
import TypeTableItem from "../../../common/TableItems/TypeTableItem";
import MethodTableItem from "../../../common/TableItems/MethodTableItem";
import MsTableOperator from "../../../../common/components/MsTableOperator";
export default { export default {
name: "TestPlanTestCaseList", name: "TestPlanTestCaseList",
components: {PlanNodeTree, StatusEdit, ExecutorEdit, MsTipButton, MsTablePagination, components: {
MsTableOperator,
MethodTableItem,
TypeTableItem,
StatusTableItem,
PriorityTableItem, StatusEdit, ExecutorEdit, MsTipButton, MsTablePagination,
TestPlanTestCaseEdit, MsTableHeader, NodeBreadcrumb, MsTableButton}, TestPlanTestCaseEdit, MsTableHeader, NodeBreadcrumb, MsTableButton},
data() { data() {
return { return {
@ -161,7 +142,28 @@
currentPage: 1, currentPage: 1,
pageSize: 5, pageSize: 5,
total: 0, total: 0,
selectIds: new Set() selectIds: new Set(),
priorityFilters: [
{text: 'P0', value: 'P0'},
{text: 'P1', value: 'P1'},
{text: 'P2', value: 'P2'}
],
methodFilters: [
{text: this.$t('test_track.case.manual'), value: 'manual'},
{text: this.$t('test_track.case.auto'), value: 'auto'}
],
typeFilters: [
{text: this.$t('commons.functional'), value: 'functional'},
{text: this.$t('commons.performance'), value: 'performance'},
{text: this.$t('commons.api'), value: 'api'}
],
statusFilters: [
{text: this.$t('test_track.plan.plan_status_prepare'), value: 'Prepare'},
{text: this.$t('test_track.plan_view.pass'), value: 'Pass'},
{text: this.$t('test_track.plan_view.failure'), value: 'Failure'},
{text: this.$t('test_track.plan_view.blocking'), value: 'Blocking'},
{text: this.$t('test_track.plan_view.skip'), value: 'Skip'},
]
} }
}, },
props:{ props:{
@ -267,6 +269,10 @@
this.condition.executor = null; this.condition.executor = null;
} }
this.initTableData(); this.initTableData();
},
filter(value, row, column) {
const property = column['property'];
return row[property] === value;
} }
} }
} }

View File

@ -171,6 +171,7 @@ export default {
'resource_pool_is_null': '资源池为空', 'resource_pool_is_null': '资源池为空',
}, },
api_test: { api_test: {
save_and_run: "保存并执行",
input_name: "请输入测试名称", input_name: "请输入测试名称",
select_project: "请选择项目", select_project: "请选择项目",
scenario: { scenario: {