测试计划详情
This commit is contained in:
parent
192b4fe457
commit
c6e384cdbd
|
@ -0,0 +1,14 @@
|
|||
package io.metersphere.base.mapper.ext;
|
||||
|
||||
import io.metersphere.base.domain.TestCase;
|
||||
import io.metersphere.controller.request.ReportRequest;
|
||||
import io.metersphere.controller.request.testcase.QueryTestCaseRequest;
|
||||
import io.metersphere.dto.ReportDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ExtTestCaseMapper {
|
||||
|
||||
List<TestCase> getTestCaseNames(@Param("request") QueryTestCaseRequest request);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="io.metersphere.base.mapper.ext.ExtTestCaseMapper">
|
||||
|
||||
<select id="getTestCaseNames" resultType="io.metersphere.base.domain.TestCase">
|
||||
select test_case.id, test_case.name
|
||||
from test_case
|
||||
<where>
|
||||
<if test="request.projectId != null">
|
||||
AND test_case.project_id = #{request.projectId}
|
||||
</if>
|
||||
<if test="request.nodeIds != null and request.nodeIds.size() > 0">
|
||||
AND test_case.node_id IN
|
||||
<foreach collection="request.nodeIds" open="(" close=")" separator="," item="nodeId">
|
||||
#{nodeId}
|
||||
</foreach>
|
||||
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY test_case.update_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -38,6 +38,11 @@ public class TestCaseController {
|
|||
return testCaseService.getTestCaseByNodeId(nodeIds);
|
||||
}
|
||||
|
||||
@PostMapping("/name/all")
|
||||
public List<TestCase> getTestCaseNames(@RequestBody QueryTestCaseRequest request){
|
||||
return testCaseService.getTestCaseNames(request);
|
||||
}
|
||||
|
||||
@PostMapping("/get/{testCaseId}")
|
||||
public List<TestCaseWithBLOBs> getTestCase(@PathVariable String testCaseId){
|
||||
return testCaseService.getTestCase(testCaseId);
|
||||
|
|
|
@ -8,6 +8,16 @@ public class QueryTestCaseRequest extends TestCase {
|
|||
|
||||
List<Integer> nodeIds;
|
||||
|
||||
String planId;
|
||||
|
||||
public String getPlanId() {
|
||||
return planId;
|
||||
}
|
||||
|
||||
public void setPlanId(String planId) {
|
||||
this.planId = planId;
|
||||
}
|
||||
|
||||
public List<Integer> getNodeIds() {
|
||||
return nodeIds;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@ package io.metersphere.service;
|
|||
import io.metersphere.base.domain.TestCase;
|
||||
import io.metersphere.base.domain.TestCaseExample;
|
||||
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
||||
import io.metersphere.base.domain.TestPlan;
|
||||
import io.metersphere.base.mapper.TestCaseMapper;
|
||||
import io.metersphere.base.mapper.TestPlanMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
|
||||
import io.metersphere.controller.request.testcase.QueryTestCaseRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@ -21,6 +24,12 @@ public class TestCaseService {
|
|||
@Resource
|
||||
TestCaseMapper testCaseMapper;
|
||||
|
||||
@Resource
|
||||
ExtTestCaseMapper extTestCaseMapper;
|
||||
|
||||
@Resource
|
||||
TestPlanMapper testPlanMapper;
|
||||
|
||||
public void addTestCase(TestCaseWithBLOBs testCase) {
|
||||
testCase.setId(UUID.randomUUID().toString());
|
||||
testCase.setCreateTime(System.currentTimeMillis());
|
||||
|
@ -63,4 +72,13 @@ public class TestCaseService {
|
|||
}
|
||||
return testCaseMapper.selectByExampleWithBLOBs(testCaseExample);
|
||||
}
|
||||
|
||||
public List<TestCase> getTestCaseNames(QueryTestCaseRequest request) {
|
||||
|
||||
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getPlanId());
|
||||
|
||||
request.setProjectId(testPlan.getProjectId());
|
||||
|
||||
return extTestCaseMapper.getTestCaseNames(request);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<el-menu :unique-opened="true" mode="horizontal" active-text-color="write"
|
||||
class="project_menu">
|
||||
<el-submenu index="1" popper-class="submenu" v-permission="['test_user', 'test_viewer']">
|
||||
<el-submenu index="1" popper-class="submenu">
|
||||
<template slot="title">
|
||||
{{currentProject == null ? '' : currentProject.name}}
|
||||
</template>
|
||||
|
@ -78,8 +78,6 @@
|
|||
},
|
||||
watch: {
|
||||
'$route'(to, from) {
|
||||
console.log(from);
|
||||
console.log(to);
|
||||
if (from.name.indexOf("Project") > 0){
|
||||
this.getProjects();
|
||||
}
|
||||
|
|
|
@ -7,11 +7,20 @@
|
|||
:plan-id="planId"
|
||||
class="node_tree"
|
||||
@nodeSelectEvent="get"
|
||||
@refresh="refresh"
|
||||
ref="nodeTree"></plan-node-tree>
|
||||
</el-aside>
|
||||
|
||||
<el-main>
|
||||
<test-case-plan-list
|
||||
@openTestCaseRelevanceDialog="openTestCaseRelevanceDialog"
|
||||
ref="testCasePlanList"></test-case-plan-list>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
<test-case-relevance
|
||||
@refresh="getCaseByNodeIds"
|
||||
ref="testCaseRelevance"></test-case-relevance>
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
@ -19,10 +28,12 @@
|
|||
<script>
|
||||
|
||||
import PlanNodeTree from "./components/PlanNodeTree";
|
||||
import TestCasePlanList from "./components/TestCasePlanList";
|
||||
import TestCaseRelevance from "./components/TestCaseRelevance";
|
||||
|
||||
export default {
|
||||
name: "TestPlanView",
|
||||
components: {PlanNodeTree},
|
||||
components: {PlanNodeTree, TestCasePlanList, TestCaseRelevance},
|
||||
data() {
|
||||
return {
|
||||
currentProject: {}
|
||||
|
@ -39,6 +50,13 @@
|
|||
},
|
||||
get() {
|
||||
|
||||
},
|
||||
openTestCaseRelevanceDialog(data) {
|
||||
this.$refs.testCaseRelevance.dialogFormVisible = true;
|
||||
this.$refs.testCaseRelevance.getCaseNames(this.planId);
|
||||
},
|
||||
getCaseByNodeIds() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,12 +12,10 @@
|
|||
:expand-on-click-node="false"
|
||||
draggable
|
||||
ref="tree">
|
||||
|
||||
<span class="custom-tree-node father" slot-scope="{node}" @click="selectNode(node)">
|
||||
{{node.label}}
|
||||
</span>
|
||||
</el-tree>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -56,8 +54,6 @@
|
|||
}
|
||||
},
|
||||
created() {
|
||||
console.log("created");
|
||||
console.log(this.planId);
|
||||
this.getNodeTree();
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
<template>
|
||||
|
||||
<el-main>
|
||||
<el-card>
|
||||
<div slot="header">
|
||||
<el-row type="flex" justify="space-between" align="middle">
|
||||
<el-col :span="5">
|
||||
<span class="title">{{$t('test_track.test_case')}}</span>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="1" :offset="8">
|
||||
<el-button icon="el-icon-circle-plus-outline" size="small" round
|
||||
@click="$emit('openTestCaseRelevanceDialog')" >{{$t('commons.create')}}</el-button>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="1" >
|
||||
<el-button
|
||||
icon="el-icon-refresh" size="small" round
|
||||
@click="initTableData()">{{$t('commons.refresh')}}</el-button>
|
||||
</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="search" clearable/>
|
||||
</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
:data="tableData"
|
||||
class="test-content">
|
||||
<el-table-column
|
||||
prop="name"
|
||||
:label="$t('commons.name')"
|
||||
width="120"
|
||||
show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="priority"
|
||||
:label="$t('test_track.priority')"
|
||||
width="120"
|
||||
show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="type"
|
||||
:label="$t('test_track.type')"
|
||||
width="120"
|
||||
show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.type == 'functional'">{{$t('commons.functional')}}</span>
|
||||
<span v-if="scope.row.type == 'performance'">{{$t('commons.performance')}}</span>
|
||||
<span v-if="scope.row.type == 'interface'">{{$t('commons.interface')}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="method"
|
||||
:label="$t('test_track.method')"
|
||||
width="120"
|
||||
show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<span v-if="scope.row.method == 'manual'">{{$t('test_track.manual')}}</span>
|
||||
<span v-if="scope.row.method == 'auto'">{{$t('test_track.auto')}}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="nodePath"
|
||||
:label="$t('test_track.module')"
|
||||
width="160"
|
||||
show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
width="160"
|
||||
:label="$t('commons.create_time')">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
width="160"
|
||||
:label="$t('commons.update_time')">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
width="100"
|
||||
: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>
|
||||
</el-main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {CURRENT_PROJECT} from '../../../../../common/constants';
|
||||
import PlanNodeTree from './PlanNodeTree';
|
||||
|
||||
export default {
|
||||
name: "TestCaseList",
|
||||
components: {PlanNodeTree},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
deletePath: "/test/case/delete",
|
||||
condition: "",
|
||||
tableData: [],
|
||||
multipleSelection: [],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
total: 0,
|
||||
loadingRequire: {project: true, testCase: true},
|
||||
testId: null
|
||||
}
|
||||
},
|
||||
created: function () {
|
||||
this.initTableData();
|
||||
},
|
||||
methods: {
|
||||
initTableData(nodeIds) {
|
||||
let param = {
|
||||
name: this.condition,
|
||||
};
|
||||
param.nodeIds = nodeIds;
|
||||
|
||||
if(localStorage.getItem(CURRENT_PROJECT)) {
|
||||
param.projectId = JSON.parse(localStorage.getItem(CURRENT_PROJECT)).id;
|
||||
}
|
||||
|
||||
this.$post(this.buildPagePath('/test/case/list'), param, response => {
|
||||
this.loadingRequire.testCase = false;
|
||||
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(testCase) {
|
||||
this.$emit('testCaseRelevance', testCase);
|
||||
},
|
||||
handleDelete(testCase) {
|
||||
this.$alert(this.$t('load_test.delete_confirm') + testCase.name + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
this._handleDelete(testCase);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
_handleDelete(testCase) {
|
||||
let testCaseId = testCase.id;
|
||||
this.$post('/test/case/delete/' + testCaseId, {}, () => {
|
||||
this.initTableData();
|
||||
this.$message({
|
||||
message: this.$t('commons.delete_success'),
|
||||
type: 'success'
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.table-page {
|
||||
padding-top: 20px;
|
||||
margin-right: -9px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,201 @@
|
|||
<template>
|
||||
|
||||
<div>
|
||||
|
||||
<el-dialog :title="$t('test_track.create')"
|
||||
:visible.sync="dialogFormVisible"
|
||||
width="65%">
|
||||
|
||||
<el-container style="min-height: 350px">
|
||||
<el-aside class="node_tree" width="200px" style="background-color: rgb(238, 241, 246)">
|
||||
<plan-node-tree></plan-node-tree>
|
||||
</el-aside>
|
||||
|
||||
<el-container>
|
||||
<el-header >
|
||||
<el-checkbox ></el-checkbox>
|
||||
</el-header>
|
||||
<el-main style="height: 100px;">
|
||||
<el-scrollbar style="height:100%">
|
||||
<el-table
|
||||
:data="testCases">
|
||||
<el-table-column
|
||||
prop="name"
|
||||
style="width: 100%">
|
||||
<template slot="header">
|
||||
<el-checkbox v-model="checkAll"></el-checkbox>
|
||||
用例名称
|
||||
</template>
|
||||
<template slot-scope="scope">
|
||||
<el-checkbox v-model="scope.row.checked"></el-checkbox>
|
||||
{{scope.row.name}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-scrollbar>
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
</el-container>
|
||||
|
||||
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button
|
||||
@click="dialogFormVisible = false">
|
||||
{{$t('test_track.cancel')}}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="saveCase">
|
||||
{{$t('test_track.confirm')}}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import {CURRENT_PROJECT} from '../../../../../common/constants';
|
||||
import PlanNodeTree from './PlanNodeTree';
|
||||
|
||||
export default {
|
||||
name: "TestCaseEdit",
|
||||
components: {PlanNodeTree},
|
||||
data() {
|
||||
return {
|
||||
dialogFormVisible: false,
|
||||
count: 6,
|
||||
checkAll: false,
|
||||
testCases: [],
|
||||
form: {
|
||||
name: '',
|
||||
}
|
||||
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
openTestCaseEditDialog(testCase) {
|
||||
this.resetForm();
|
||||
this.operationType = 'add';
|
||||
if(testCase){
|
||||
//修改
|
||||
this.operationType = 'edit';
|
||||
let tmp = {};
|
||||
Object.assign(tmp, testCase);
|
||||
tmp.steps = JSON.parse(testCase.steps);
|
||||
Object.assign(this.form, tmp);
|
||||
this.form.module = testCase.nodeId;
|
||||
}
|
||||
this.dialogFormVisible = true;
|
||||
},
|
||||
handleAddStep(index, data) {
|
||||
let step = {};
|
||||
step.num = data.num + 1;
|
||||
step.desc = null;
|
||||
step.result = null;
|
||||
this.form.steps.forEach(step => {
|
||||
if(step.num > data.num){
|
||||
step.num ++;
|
||||
}
|
||||
});
|
||||
this.form.steps.push(step);
|
||||
},
|
||||
handleDeleteStep(index, data) {
|
||||
this.form.steps.splice(index, 1);
|
||||
this.form.steps.forEach(step => {
|
||||
if(step.num > data.num){
|
||||
step.num --;
|
||||
}
|
||||
});
|
||||
},
|
||||
saveCase(){
|
||||
this.$refs['relevanceFrom'].validate((valid) => {
|
||||
if (valid) {
|
||||
let param = {};
|
||||
Object.assign(param, this.form);
|
||||
param.steps = JSON.stringify(this.form.steps);
|
||||
param.nodeId = this.form.module;
|
||||
this.moduleOptions.forEach(item => {
|
||||
if(this.form.module === item.id){
|
||||
param.nodePath = item.path;
|
||||
}
|
||||
});
|
||||
if(localStorage.getItem(CURRENT_PROJECT)) {
|
||||
param.projectId = JSON.parse(localStorage.getItem(CURRENT_PROJECT)).id;
|
||||
}
|
||||
this.$post('/test/case/' + this.operationType, param, () => {
|
||||
this.$message.success(this.$t('commons.save_success'));
|
||||
this.dialogFormVisible = false;
|
||||
this.$emit("refresh");
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
,
|
||||
resetForm() {
|
||||
if (this.$refs['relevanceFrom']) {
|
||||
this.$refs['relevanceFrom'].resetFields();
|
||||
}
|
||||
|
||||
},
|
||||
load () {
|
||||
this.count += 2
|
||||
},
|
||||
getCaseNames(planId) {
|
||||
if(planId){
|
||||
let param = {};
|
||||
param.planId = planId;
|
||||
this.$post('/test/case/name/all', param, response => {
|
||||
this.testCases = response.data;
|
||||
this.testCases.forEach(item => {
|
||||
item.checked = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.tb-edit .el-input {
|
||||
display: none;
|
||||
color: black;
|
||||
}
|
||||
.tb-edit .current-row .el-input {
|
||||
display: block;
|
||||
|
||||
}
|
||||
.tb-edit .current-row .el-input+span {
|
||||
display: none;
|
||||
|
||||
}
|
||||
|
||||
.node_tree{
|
||||
/*border-radius: 1px;*/
|
||||
/*padding-top: 5px ;*/
|
||||
/*height: 100%;*/
|
||||
/*box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);*/
|
||||
}
|
||||
|
||||
.el-header {
|
||||
background-color: darkgrey;
|
||||
color: #333;
|
||||
line-height: 60px;
|
||||
height: 1%;
|
||||
}
|
||||
|
||||
.el-aside {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
</style>
|
Loading…
Reference in New Issue