feat: 脑图用例编辑

This commit is contained in:
chenjianxing 2021-03-15 16:20:51 +08:00
parent 82b004df60
commit b5709cc998
7 changed files with 226 additions and 43 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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