feat: 用例编辑支持上一条下一条

This commit is contained in:
chenjianxing 2021-01-22 16:30:49 +08:00
parent b7900468e1
commit 6243e3a410
9 changed files with 205 additions and 60 deletions

View File

@ -268,7 +268,14 @@
<select id="list" resultType="io.metersphere.track.dto.TestCaseDTO">
select
<include refid="io.metersphere.base.mapper.TestCaseMapper.Base_Column_List"/>
<if test="request.selectFields != null and request.selectFields.size() > 0">
<foreach collection="request.selectFields" item="field" separator=",">
${field}
</foreach>
</if>
<if test="request.selectFields == null or request.selectFields.size() == 0">
<include refid="io.metersphere.base.mapper.TestCaseMapper.Base_Column_List"/>
</if>
from test_case
<where>
<if test="request.combine != null">

View File

@ -14,10 +14,12 @@ import io.metersphere.excel.domain.ExcelResponse;
import io.metersphere.service.CheckPermissionService;
import io.metersphere.service.FileService;
import io.metersphere.track.dto.TestCaseDTO;
import io.metersphere.track.dto.TestPlanCaseDTO;
import io.metersphere.track.request.testcase.EditTestCaseRequest;
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
import io.metersphere.track.request.testplan.FileOperationRequest;
import io.metersphere.track.request.testplancase.QueryTestPlanCaseRequest;
import io.metersphere.track.service.TestCaseService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
@ -65,6 +67,11 @@ public class TestCaseController {
return testCaseService.listTestCaseMthod(request);
}
@PostMapping("/list/ids")
public List<TestCaseDTO> getTestPlanCaseIds(@RequestBody QueryTestCaseRequest request) {
return testCaseService.listTestCaseIds(request);
}
@GetMapping("recent/{count}")
public List<TestCase> recentTestPlans(@PathVariable int count) {

View File

@ -22,6 +22,8 @@ public class QueryTestCaseRequest extends TestCase {
private Map<String, List<String>> filters;
private List<String> selectFields;
private String planId;
private String workspaceId;

View File

@ -676,4 +676,19 @@ public class TestCaseService {
editTestCase(request);
return request.getId();
}
public List<TestCaseDTO> listTestCaseIds(QueryTestCaseRequest request) {
List<OrderRequest> orderList = ServiceUtils.getDefaultOrder(request.getOrders());
OrderRequest order = new OrderRequest();
// 对模板导入的测试用例排序
order.setName("sort");
order.setType("desc");
orderList.add(order);
request.setOrders(orderList);
List<String> selectFields = new ArrayList<>();
selectFields.add("id");
selectFields.add("name");
request.setSelectFields(selectFields);
return extTestCaseMapper.list(request);
}
}

View File

@ -0,0 +1,57 @@
<template>
<span class="previous-next-button">
<span class="head-right-tip" v-if="index + 1 === list.length">
{{ $t('test_track.plan_view.pre_case') }} : {{list[index - 1] ? list[index - 1].name : ''}}
</span>
<span class="head-right-tip" v-if="index + 1 !== list.length">
{{ $t('test_track.plan_view.next_case') }} : {{list[index + 1] ? list[index + 1].name : ''}}
</span>
<el-button plain size="mini" icon="el-icon-arrow-up" :disabled="index + 1 <= 1" @click="handlePre()"/>
<span>
{{ index + 1 }}/{{ list.length }}
</span>
<el-button plain size="mini" icon="el-icon-arrow-down" :disabled="index + 1 >= list.length" @click="handleNext()"/>
</span>
</template>
<script>
export default {
name: "MsPreviousNextButton",
data() {
return {
}
},
props: {
list: {
type: Array,
default() {
return []
}
},
index: {
type: Number,
default() {
return 0
}
}
},
methods: {
handlePre() {
this.$emit('pre');
},
handleNext() {
this.$emit('next');
}
}
}
</script>
<style scoped>
.head-right-tip {
color: darkgrey;
}
</style>

View File

@ -21,6 +21,7 @@
@refresh="refresh"
@refreshAll="refreshAll"
@moveToNode="moveToNode"
@setCondition="setCondition"
ref="testCaseList">
</test-case-list>
</ms-main-container>
@ -30,6 +31,7 @@
:read-only="testCaseReadOnly"
:tree-nodes="treeNodes"
:select-node="selectNode"
:select-condition="condition"
ref="testCaseEditDialog">
</test-case-edit>
@ -73,6 +75,7 @@ export default {
selectParentNodes: [],
testCaseReadOnly: true,
selectNode: {},
condition: {}
}
},
mounted() {
@ -165,6 +168,9 @@ export default {
setTreeNodes(data) {
this.treeNodes = data;
},
setCondition(data) {
this.condition = data;
},
moveSave(param) {
this.result = this.$post('/test/case/batch/edit', param, () => {
this.$success(this.$t('commons.save_success'));

View File

@ -5,6 +5,19 @@
:title="operationType == 'edit' ? ( readOnly ? $t('test_track.case.view_case') : $t('test_track.case.edit_case')) : $t('test_track.case.create')"
:visible.sync="dialogFormVisible" width="85%" v-if="dialogFormVisible">
<template v-slot:title>
<el-row>
<el-col :span="4">
<span>
{{operationType == 'edit' ? ( readOnly ? $t('test_track.case.view_case') : $t('test_track.case.edit_case')) : $t('test_track.case.create')}}
</span>
</el-col>
<el-col class="head-right" :span="19">
<ms-previous-next-button v-if="operationType = 'edit'" :index="index" @pre="handlePre" @next="handleNext" :list="testCases"/>
</el-col>
</el-row>
</template>
<el-row :gutter="10">
<div>
<el-col :span="17">
@ -279,10 +292,11 @@ import {getCurrentProjectID} from "../../../../../common/js/utils";
import {buildNodePath} from "../../../api/definition/model/NodeTree";
import CaseComment from "@/business/components/track/case/components/CaseComment";
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
import MsPreviousNextButton from "../../../common/components/MsPreviousNextButton";
export default {
name: "TestCaseEdit",
components: {MsInputTag, CaseComment, MsDialogFooter, TestCaseAttachment},
components: {MsPreviousNextButton, MsInputTag, CaseComment, MsDialogFooter, TestCaseAttachment},
data() {
return {
result: {},
@ -335,6 +349,8 @@ export default {
{value: 'manual', label: this.$t('test_track.case.manual')}
],
testCase: {},
testCases: [],
index: 0
};
},
props: {
@ -348,6 +364,9 @@ export default {
selectNode: {
type: Object
},
selectCondition: {
type: Object
},
},
mounted() {
this.getSelectOptions();
@ -363,18 +382,12 @@ export default {
this.$nextTick(() => (this.isStepTableAlive = true));
},
open(testCase) {
this.testCase = {};
if (testCase) {
testCase.tags = JSON.parse(testCase.tags);
//
this.testCase = testCase.isCopy ? {} : testCase;
}
this.resetForm();
this.projectId = getCurrentProjectID();
if (window.history && window.history.pushState) {
history.pushState(null, null, document.URL);
window.addEventListener('popstate', this.close);
}
this.resetForm();
listenGoBack(this.close);
this.operationType = 'add';
if (testCase) {
@ -383,13 +396,13 @@ export default {
//
if (testCase.name === '') {
this.operationType = 'add';
this.setFormData(testCase);
this.setTestCaseExtInfo(testCase);
this.getSelectOptions();
this.reload();
} else {
this.initTestCases(testCase);
}
let tmp = {};
Object.assign(tmp, testCase);
tmp.steps = JSON.parse(testCase.steps);
Object.assign(this.form, tmp);
this.form.module = testCase.nodeId;
this.getFileMetaData(testCase);
} else {
if (this.selectNode.data) {
this.form.module = this.selectNode.data.id;
@ -403,12 +416,56 @@ export default {
this.form.type = 'functional';
this.form.method = 'manual';
this.form.maintainer = user.id;
this.getSelectOptions();
this.reload();
}
this.getSelectOptions();
this.reload();
this.dialogFormVisible = true;
},
handlePre() {
this.index--;
this.getTestCase(this.index)
},
handleNext() {
this.index++;
this.getTestCase(this.index);
},
initTestCases(testCase) {
this.result = this.$post('/test/case/list/ids', this.selectCondition, response => {
this.testCases = response.data;
for (let i = 0; i < this.testCases.length; i++) {
if (this.testCases[i].id === testCase.id) {
this.index = i;
this.getTestCase(i);
}
}
});
},
getTestCase(index) {
let testCase = this.testCases[index];
this.result = this.$get('/test/case/get/' + testCase.id, response => {
let testCase = response.data;
this.setFormData(testCase);
this.setTestCaseExtInfo(testCase);
this.getSelectOptions();
this.reload();
})
},
setFormData(testCase) {
testCase.tags = JSON.parse(testCase.tags);
let tmp = {};
Object.assign(tmp, testCase);
tmp.steps = JSON.parse(testCase.steps);
Object.assign(this.form, tmp);
this.form.module = testCase.nodeId;
this.getFileMetaData(testCase);
},
setTestCaseExtInfo (testCase) {
this.testCase = {};
if (testCase) {
//
this.testCase = testCase.isCopy ? {} : testCase;
}
},
getFileMetaData(testCase) {
this.fileList = [];
this.tableData = [];
@ -607,28 +664,33 @@ export default {
if (this.$refs['caseFrom']) {
this.$refs['caseFrom'].validate((valid) => {
this.$refs['caseFrom'].resetFields();
this.form.name = '';
this.form.module = '';
this.form.type = '';
this.form.method = '';
this.form.maintainer = '';
this.form.priority = '';
this.form.prerequisite = '';
this.form.remark = '';
this.form.testId = '';
this.form.testName = '';
this.form.steps = [{
num: 1,
desc: '',
result: ''
}];
this.uploadList = [];
this.fileList = [];
this.tableData = [];
this._resetForm();
return true;
});
} else {
this._resetForm();
}
},
_resetForm() {
this.form.name = '';
this.form.module = '';
this.form.type = '';
this.form.method = '';
this.form.maintainer = '';
this.form.priority = '';
this.form.prerequisite = '';
this.form.remark = '';
this.form.testId = '';
this.form.testName = '';
this.form.steps = [{
num: 1,
desc: '',
result: ''
}];
this.uploadList = [];
this.fileList = [];
this.tableData = [];
},
handleExceed() {
this.$error(this.$t('load_test.file_size_limit'));
},
@ -748,4 +810,8 @@ export default {
height: calc(100vh - 120px);
}
.head-right {
text-align: right;
}
</style>

View File

@ -286,12 +286,16 @@ export default {
}
},
created: function () {
this.$emit('setCondition', this.condition);
this.initTableData();
},
watch: {
selectNodeIds() {
this.currentPage = 1;
this.initTableData();
},
condition() {
this.$emit('setCondition', this.condition);
}
},
methods: {

View File

@ -20,32 +20,15 @@
<el-row type="flex" class="head-bar">
<el-col>
<el-col :span="4">
<el-button plain size="mini"
icon="el-icon-back"
@click="cancel">{{ $t('test_track.return') }}
</el-button>
</el-col>
<el-col class="head-right">
<span class="head-right-tip" v-if="index + 1 === testCases.length">
{{ $t('test_track.plan_view.pre_case') }} : {{
testCases[index - 1] ? testCases[index - 1].name : ''
}}
</span>
<span class="head-right-tip" v-if="index + 1 !== testCases.length">
{{ $t('test_track.plan_view.next_case') }} : {{
testCases[index + 1] ? testCases[index + 1].name : ''
}}
</span>
<el-button plain size="mini" icon="el-icon-arrow-up"
:disabled="index + 1 <= 1"
@click="handlePre()"/>
<span> {{ index + 1 }}/{{ testCases.length }} </span>
<el-button plain size="mini" icon="el-icon-arrow-down"
:disabled="index + 1 >= testCases.length"
@click="handleNext()"/>
<el-col class="head-right" :span="20">
<ms-previous-next-button :index="index" @pre="handlePre" @next="handleNext" :list="testCases"/>
</el-col>
</el-row>
@ -370,10 +353,12 @@ import PerformanceTestResult from "../test/PerformanceTestResult";
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
import TestCaseAttachment from "@/business/components/track/case/components/TestCaseAttachment";
import CaseComment from "@/business/components/track/case/components/CaseComment";
import MsPreviousNextButton from "../../../../../common/components/MsPreviousNextButton";
export default {
name: "FunctionalTestCaseEdit",
components: {
MsPreviousNextButton,
CaseComment,
PerformanceTestResult,
PerformanceTestDetail,
@ -722,10 +707,6 @@ export default {
float: right;
}
.head-right-tip {
color: darkgrey;
}
.el-scrollbar {
height: 100%;
}