feat: 脑图用例编辑
This commit is contained in:
parent
82b004df60
commit
b5709cc998
|
@ -18,6 +18,7 @@ import io.metersphere.track.dto.TestPlanCaseDTO;
|
||||||
import io.metersphere.track.request.testcase.EditTestCaseRequest;
|
import io.metersphere.track.request.testcase.EditTestCaseRequest;
|
||||||
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
||||||
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
|
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
|
||||||
|
import io.metersphere.track.request.testcase.TestCaseMinderEditRequest;
|
||||||
import io.metersphere.track.request.testplan.FileOperationRequest;
|
import io.metersphere.track.request.testplan.FileOperationRequest;
|
||||||
import io.metersphere.track.request.testplancase.QueryTestPlanCaseRequest;
|
import io.metersphere.track.request.testplancase.QueryTestPlanCaseRequest;
|
||||||
import io.metersphere.track.service.TestCaseService;
|
import io.metersphere.track.service.TestCaseService;
|
||||||
|
@ -59,6 +60,12 @@ public class TestCaseController {
|
||||||
return testCaseService.listTestCase(request);
|
return testCaseService.listTestCase(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/list/detail/{projectId}")
|
||||||
|
public List<TestCaseWithBLOBs> listDetail(@PathVariable String projectId) {
|
||||||
|
checkPermissionService.checkProjectOwner(projectId);
|
||||||
|
return testCaseService.listTestCaseDetail(projectId);
|
||||||
|
}
|
||||||
|
|
||||||
/*jenkins项目下所有接口和性能测试用例*/
|
/*jenkins项目下所有接口和性能测试用例*/
|
||||||
@GetMapping("/list/method/{projectId}")
|
@GetMapping("/list/method/{projectId}")
|
||||||
public List<TestCaseDTO> listByMethod(@PathVariable String projectId) {
|
public List<TestCaseDTO> listByMethod(@PathVariable String projectId) {
|
||||||
|
@ -195,4 +202,11 @@ public class TestCaseController {
|
||||||
return testCaseService.addTestCase(testCaseWithBLOBs);
|
return testCaseService.addTestCase(testCaseWithBLOBs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/minder/edit")
|
||||||
|
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||||
|
public void minderEdit(@RequestBody TestCaseMinderEditRequest request) {
|
||||||
|
testCaseService.minderEdit(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package io.metersphere.track.request.testcase;
|
||||||
|
|
||||||
|
import io.metersphere.base.domain.TestCaseWithBLOBs;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class TestCaseMinderEditRequest {
|
||||||
|
private String projectId;
|
||||||
|
List<TestCaseWithBLOBs> data;
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ import io.metersphere.track.dto.TestCaseDTO;
|
||||||
import io.metersphere.track.request.testcase.EditTestCaseRequest;
|
import io.metersphere.track.request.testcase.EditTestCaseRequest;
|
||||||
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
|
||||||
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
|
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
|
||||||
|
import io.metersphere.track.request.testcase.TestCaseMinderEditRequest;
|
||||||
import io.metersphere.xmind.XmindCaseParser;
|
import io.metersphere.xmind.XmindCaseParser;
|
||||||
import org.apache.commons.collections4.ListUtils;
|
import org.apache.commons.collections4.ListUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -705,4 +706,23 @@ public class TestCaseService {
|
||||||
return extTestCaseMapper.list(request);
|
return extTestCaseMapper.list(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<TestCaseWithBLOBs> listTestCaseDetail(String projectId) {
|
||||||
|
TestCaseExample testCaseExample = new TestCaseExample();
|
||||||
|
testCaseExample.createCriteria().andProjectIdEqualTo(projectId);
|
||||||
|
return testCaseMapper.selectByExampleWithBLOBs(testCaseExample);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void minderEdit(TestCaseMinderEditRequest request) {
|
||||||
|
List<TestCaseWithBLOBs> data = request.getData();
|
||||||
|
data.forEach(item -> {
|
||||||
|
item.setProjectId(request.getProjectId());
|
||||||
|
if (StringUtils.isBlank(item.getId()) || item.getId().length() < 20) {
|
||||||
|
item.setId(UUID.randomUUID().toString());
|
||||||
|
item.setMaintainer(SessionUtils.getUserId());
|
||||||
|
addTestCase(item);
|
||||||
|
} else {
|
||||||
|
editTestCase(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="minder">
|
<div class="minder">
|
||||||
<minder-editor v-if="isActive"
|
<minder-editor
|
||||||
|
v-if="isActive"
|
||||||
class="minder-container"
|
class="minder-container"
|
||||||
:import-json="importJson"
|
:import-json="importJson"
|
||||||
|
:height="700"
|
||||||
@save="save"
|
@save="save"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,10 +22,10 @@ export default {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data: {
|
dataMap: {
|
||||||
type: Array,
|
type: Map,
|
||||||
default() {
|
default() {
|
||||||
return []
|
return new Map();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -52,7 +54,9 @@ export default {
|
||||||
root: {
|
root: {
|
||||||
data: {
|
data: {
|
||||||
text: "全部用例",
|
text: "全部用例",
|
||||||
disable: true
|
disable: true,
|
||||||
|
id: "root",
|
||||||
|
path: ""
|
||||||
},
|
},
|
||||||
children: []
|
children: []
|
||||||
},
|
},
|
||||||
|
@ -62,33 +66,46 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
dataMap() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.parse(this.importJson.root, this.treeNodes);
|
this.parse(this.importJson.root, this.treeNodes);
|
||||||
this.reload();
|
this.reload();
|
||||||
})
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
save(data) {
|
save(data) {
|
||||||
console.log(data);
|
this.$emit('save', data)
|
||||||
// console.log(this.treeNodes);
|
|
||||||
},
|
},
|
||||||
parse(root, children) {
|
parse(root, children) {
|
||||||
|
root.children = [];
|
||||||
|
// 添加数据节点
|
||||||
|
let dataNodes = this.dataMap.get(root.data.id);
|
||||||
|
if (dataNodes) {
|
||||||
|
dataNodes.forEach((dataNode) => {
|
||||||
|
root.children.push(dataNode);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (children == null || children.length < 1) {
|
if (children == null || children.length < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
root.children = [];
|
|
||||||
children.forEach((item) => {
|
children.forEach((item) => {
|
||||||
let node = {
|
let node = {
|
||||||
data: {
|
data: {
|
||||||
text: item.name,
|
text: item.name,
|
||||||
id: item.id,
|
id: item.id,
|
||||||
disable: true,
|
disable: true,
|
||||||
// resource: ['#']
|
path: root.data.path + "/" + item.name,
|
||||||
|
expandState:"collapse"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
root.children.push(node);
|
root.children.push(node);
|
||||||
this.parse(node, item.children);
|
this.parse(node, item.children);
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
reload() {
|
reload() {
|
||||||
this.isActive = false;
|
this.isActive = false;
|
||||||
|
@ -101,4 +118,9 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.minder-container >>> .save-btn {
|
||||||
|
right: 30px;
|
||||||
|
bottom: auto;
|
||||||
|
top: 30px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -39,8 +39,9 @@
|
||||||
@setCondition="setCondition"
|
@setCondition="setCondition"
|
||||||
ref="testCaseList">
|
ref="testCaseList">
|
||||||
</test-case-list>
|
</test-case-list>
|
||||||
<testcase-minder
|
<test-case-minder
|
||||||
:tree-nodes="treeNodes"
|
:tree-nodes="treeNodes"
|
||||||
|
:project-id="projectId"
|
||||||
v-if="activeDom === 'right'"
|
v-if="activeDom === 'right'"
|
||||||
ref="testCaseList"/>
|
ref="testCaseList"/>
|
||||||
</ms-tab-button>
|
</ms-tab-button>
|
||||||
|
@ -97,17 +98,17 @@ import SelectMenu from "../common/SelectMenu";
|
||||||
import MsContainer from "../../common/components/MsContainer";
|
import MsContainer from "../../common/components/MsContainer";
|
||||||
import MsAsideContainer from "../../common/components/MsAsideContainer";
|
import MsAsideContainer from "../../common/components/MsAsideContainer";
|
||||||
import MsMainContainer from "../../common/components/MsMainContainer";
|
import MsMainContainer from "../../common/components/MsMainContainer";
|
||||||
import {checkoutTestManagerOrTestUser, getCurrentProjectID, getUUID, hasRoles} from "../../../../common/js/utils";
|
import {checkoutTestManagerOrTestUser, getCurrentProjectID, getUUID} from "../../../../common/js/utils";
|
||||||
import TestCaseNodeTree from "../common/TestCaseNodeTree";
|
import TestCaseNodeTree from "../common/TestCaseNodeTree";
|
||||||
import {TrackEvent,LIST_CHANGE} from "@/business/components/common/head/ListEvent";
|
|
||||||
import TestcaseMinder from "@/business/components/common/components/MsModuleMinder";
|
|
||||||
import MsTabButton from "@/business/components/common/components/MsTabButton";
|
import MsTabButton from "@/business/components/common/components/MsTabButton";
|
||||||
|
import TestCaseMinder from "@/business/components/track/case/components/minder/TestCaseMinder";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "TestCase",
|
name: "TestCase",
|
||||||
components: {
|
components: {
|
||||||
|
TestCaseMinder,
|
||||||
MsTabButton,
|
MsTabButton,
|
||||||
TestcaseMinder,
|
|
||||||
TestCaseNodeTree,
|
TestCaseNodeTree,
|
||||||
MsMainContainer,
|
MsMainContainer,
|
||||||
MsAsideContainer, MsContainer, TestCaseList, NodeTree, TestCaseEdit, SelectMenu
|
MsAsideContainer, MsContainer, TestCaseList, NodeTree, TestCaseEdit, SelectMenu
|
||||||
|
@ -129,11 +130,13 @@ export default {
|
||||||
renderComponent:true,
|
renderComponent:true,
|
||||||
loading: false,
|
loading: false,
|
||||||
type:'',
|
type:'',
|
||||||
activeDom: 'left'
|
activeDom: 'left',
|
||||||
|
projectId: ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.init(this.$route);
|
this.init(this.$route);
|
||||||
|
this.projectId = getCurrentProjectID();
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
redirectID() {
|
redirectID() {
|
||||||
|
@ -193,7 +196,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addTab(tab) {
|
addTab(tab) {
|
||||||
if (!getCurrentProjectID()) {
|
if (!this.projectId) {
|
||||||
this.$warning(this.$t('commons.check_project_tip'));
|
this.$warning(this.$t('commons.check_project_tip'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -253,7 +256,7 @@ export default {
|
||||||
this.testCaseReadOnly = true;
|
this.testCaseReadOnly = true;
|
||||||
}
|
}
|
||||||
let caseId = this.$route.params.caseId;
|
let caseId = this.$route.params.caseId;
|
||||||
if (!getCurrentProjectID()) {
|
if (!this.projectId) {
|
||||||
this.$warning(this.$t('commons.check_project_tip'));
|
this.$warning(this.$t('commons.check_project_tip'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -472,7 +472,6 @@ export default {
|
||||||
reload() {
|
reload() {
|
||||||
this.isStepTableAlive = false;
|
this.isStepTableAlive = false;
|
||||||
this.$nextTick(() => (this.isStepTableAlive = true));
|
this.$nextTick(() => (this.isStepTableAlive = true));
|
||||||
console.log(this.form)
|
|
||||||
},
|
},
|
||||||
open(testCase) {
|
open(testCase) {
|
||||||
this.projectId = getCurrentProjectID();
|
this.projectId = getCurrentProjectID();
|
||||||
|
@ -552,9 +551,7 @@ export default {
|
||||||
let tmp = {};
|
let tmp = {};
|
||||||
Object.assign(tmp, testCase);
|
Object.assign(tmp, testCase);
|
||||||
tmp.steps = JSON.parse(testCase.steps);
|
tmp.steps = JSON.parse(testCase.steps);
|
||||||
console.log(tmp)
|
|
||||||
Object.assign(this.form, tmp);
|
Object.assign(this.form, tmp);
|
||||||
console.log(this.form)
|
|
||||||
this.form.module = testCase.nodeId;
|
this.form.module = testCase.nodeId;
|
||||||
this.getFileMetaData(testCase);
|
this.getFileMetaData(testCase);
|
||||||
},
|
},
|
||||||
|
@ -631,7 +628,6 @@ export default {
|
||||||
let param = this.buildParam();
|
let param = this.buildParam();
|
||||||
if (this.validate(param)) {
|
if (this.validate(param)) {
|
||||||
let option = this.getOption(param);
|
let option = this.getOption(param);
|
||||||
console.log(option)
|
|
||||||
this.result = this.$request(option, () => {
|
this.result = this.$request(option, () => {
|
||||||
this.$success(this.$t('commons.save_success'));
|
this.$success(this.$t('commons.save_success'));
|
||||||
if (this.operationType == 'add' && this.isCreateContinue) {
|
if (this.operationType == 'add' && this.isCreateContinue) {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<ms-module-minder
|
<ms-module-minder
|
||||||
:tree-nodes="treeNodes"/>
|
v-loading="result.loading"
|
||||||
|
:tree-nodes="treeNodes"
|
||||||
|
:data-map="dataMap"
|
||||||
|
@save="save"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -11,7 +15,8 @@ name: "TestCaseMinder",
|
||||||
data() {
|
data() {
|
||||||
return{
|
return{
|
||||||
testCase: [],
|
testCase: [],
|
||||||
dataMap: new Map()
|
dataMap: new Map(),
|
||||||
|
result: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
@ -25,38 +30,147 @@ name: "TestCaseMinder",
|
||||||
projectId: String
|
projectId: String
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
// this.getTestCases();
|
this.$nextTick(() => {
|
||||||
|
this.getTestCases();
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getTestCases() {
|
getTestCases() {
|
||||||
if (this.projectId) {
|
if (this.projectId) {
|
||||||
this.result = this.$get('/test/case/list/detail/' + this.projectId,response => {
|
this.result = this.$get('/test/case/list/detail/' + this.projectId,response => {
|
||||||
this.testCase = response.data;
|
this.testCase = response.data;
|
||||||
console.log(this.testCase)
|
|
||||||
this.parse();
|
this.parse();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
parse() {
|
save(data) {
|
||||||
this.testCase.forEach(item => {
|
let saveCases = [];
|
||||||
let mapItem = this.dataMap.get(item.moduleId);
|
this.buildSaveCase(data.root, saveCases, undefined);
|
||||||
let nodeItem = {
|
console.log(saveCases);
|
||||||
id: item.id,
|
let param = {
|
||||||
name: item.name,
|
projectId: this.projectId,
|
||||||
|
data: saveCases
|
||||||
}
|
}
|
||||||
if (mapItem) {
|
this.result = this.$post('/test/case/minder/edit', param, () => {
|
||||||
mapItem.push(item);
|
this.$success(this.$t('commons.save_success'));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
buildSaveCase(root, saveCases, parent) {
|
||||||
|
let data = root.data;
|
||||||
|
if (data.resource && data.resource.indexOf("用例") > -1) {
|
||||||
|
this._buildSaveCase(root, saveCases, parent);
|
||||||
} else {
|
} else {
|
||||||
mapItem = [];
|
if (root.children) {
|
||||||
mapItem.push(item);
|
root.children.forEach((childNode) => {
|
||||||
}
|
this.buildSaveCase(childNode, saveCases, root.data);
|
||||||
if (item.tags && item.tags.length > 0) {
|
|
||||||
item.tags = JSON.parse(item.tags);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
_buildSaveCase(node, saveCases, parent) {
|
||||||
|
let data = node.data;
|
||||||
|
let isChange = false;
|
||||||
|
let testCase = {
|
||||||
|
id: data.id,
|
||||||
|
name: data.text,
|
||||||
|
nodeId: parent ? parent.id : "",
|
||||||
|
nodePath: parent ? parent.path : "",
|
||||||
|
type: data.type ? data.type : 'functional',
|
||||||
|
method: data.method ? data.method: 'manual',
|
||||||
|
maintainer: data.maintainer,
|
||||||
|
priority: 'P' + data.priority,
|
||||||
|
};
|
||||||
|
if (data.changed) isChange = true;
|
||||||
|
let steps = [];
|
||||||
|
let stepNum = 1;
|
||||||
|
if (node.children) {
|
||||||
|
node.children.forEach((childNode) => {
|
||||||
|
let childData = childNode.data;
|
||||||
|
if (childData.resource && childData.resource.indexOf('前置条件') > -1) {
|
||||||
|
testCase.prerequisite = childData.text;
|
||||||
|
} else if (childData.resource && childData.resource.indexOf('备注') > -1) {
|
||||||
|
testCase.remark = childData.text;
|
||||||
|
} else {
|
||||||
|
// 测试步骤
|
||||||
|
let step = {};
|
||||||
|
step.num = stepNum++;
|
||||||
|
step.desc = childData.text;
|
||||||
|
if (childNode.children) {
|
||||||
|
let result = "";
|
||||||
|
childNode.children.forEach((child) => {
|
||||||
|
result += child.data.text;
|
||||||
|
if (child.data.changed) isChange = true;
|
||||||
|
})
|
||||||
|
step.result = result;
|
||||||
|
}
|
||||||
|
steps.push(step);
|
||||||
|
}
|
||||||
|
if (childData.changed) isChange = true;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
testCase.steps = JSON.stringify(steps);
|
||||||
|
if (isChange) {
|
||||||
|
saveCases.push(testCase);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parse() {
|
||||||
|
let dataMap = new Map();
|
||||||
|
this.testCase.forEach(item => {
|
||||||
|
item.steps = JSON.parse(item.steps);
|
||||||
|
// if (item.tags && item.tags.length > 0) {
|
||||||
|
// item.tags = JSON.parse(item.tags);
|
||||||
|
// }
|
||||||
|
let mapItem = dataMap.get(item.nodeId);
|
||||||
|
let nodeItem = {
|
||||||
|
data: {
|
||||||
|
id: item.id,
|
||||||
|
text: item.name,
|
||||||
|
priority: Number.parseInt(item.priority.substring(item.priority.length - 1 )),
|
||||||
|
resource: ["用例"],
|
||||||
|
type: item.type,
|
||||||
|
method: item.method,
|
||||||
|
maintainer: item.maintainer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.parseChildren(nodeItem, item);
|
||||||
|
if (mapItem) {
|
||||||
|
mapItem.push(nodeItem);
|
||||||
|
} else {
|
||||||
|
mapItem = [];
|
||||||
|
mapItem.push(nodeItem);
|
||||||
|
dataMap.set(item.nodeId, mapItem);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.dataMap = dataMap;
|
||||||
|
},
|
||||||
|
parseChildren(nodeItem, item) {
|
||||||
|
nodeItem.children = [];
|
||||||
|
let children = [];
|
||||||
|
this._parseChildren(children, item.prerequisite, "前置条件");
|
||||||
|
item.steps.forEach((step) => {
|
||||||
|
let descNode = this._parseChildren(children, step.desc, "测试步骤");
|
||||||
|
if (descNode) {
|
||||||
|
descNode.data.num = step.num;
|
||||||
|
descNode.children = [];
|
||||||
|
this._parseChildren(descNode.children, step.result, "预期结果");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this._parseChildren(children, item.remark, "备注");
|
||||||
|
nodeItem.children = children;
|
||||||
|
},
|
||||||
|
_parseChildren(children, k, v) {
|
||||||
|
if (k) {
|
||||||
|
let node = {
|
||||||
|
data: {
|
||||||
|
text: k,
|
||||||
|
resource: [v]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
children.push(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue