feat: 用例脑图支持添加模块

This commit is contained in:
chenjianxing 2021-11-09 19:16:05 +08:00 committed by jianxing
parent 99d6e8d171
commit a1e41339ec
12 changed files with 298 additions and 170 deletions

View File

@ -295,6 +295,7 @@ public class Swagger3Parser extends SwaggerAbstractParser {
} }
private void parseKvBody(Schema schema, Body body, Object data, Map<String, Schema> infoMap) { private void parseKvBody(Schema schema, Body body, Object data, Map<String, Schema> infoMap) {
if (data == null) return;
if (data instanceof JSONObject) { if (data instanceof JSONObject) {
((JSONObject) data).forEach((k, v) -> { ((JSONObject) data).forEach((k, v) -> {
Schema dataSchema = (Schema) v; Schema dataSchema = (Schema) v;
@ -311,6 +312,9 @@ public class Swagger3Parser extends SwaggerAbstractParser {
body.getKvs().add(kv); body.getKvs().add(kv);
}); });
} else { } else {
if (data instanceof String && StringUtils.isBlank((String) data)) {
return;
}
Schema dataSchema = (Schema) data; Schema dataSchema = (Schema) data;
KeyValue kv = new KeyValue(schema.getName(), String.valueOf(dataSchema.getExample()), schema.getDescription()); KeyValue kv = new KeyValue(schema.getName(), String.valueOf(dataSchema.getExample()), schema.getDescription());
Schema schemaInfo = infoMap.get(schema.getName()); Schema schemaInfo = infoMap.get(schema.getName());

View File

@ -1,11 +1,11 @@
package io.metersphere.controller; package io.metersphere.controller;
import io.metersphere.base.domain.MinderExtraNode; import io.metersphere.base.domain.MinderExtraNode;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.service.MinderExtraNodeService; import io.metersphere.service.MinderExtraNodeService;
import io.metersphere.track.request.MinderExtraNodeEditRequest; import org.springframework.web.bind.annotation.GetMapping;
import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.List;
@ -17,11 +17,11 @@ public class MinderExtraNodeController {
@Resource @Resource
MinderExtraNodeService minderExtraNodeService; MinderExtraNodeService minderExtraNodeService;
@PostMapping("/batch/edit") // @PostMapping("/batch/edit")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_EDIT) // @RequiresPermissions(PermissionConstants.PROJECT_TRACK_CASE_READ_EDIT)
public void minderEdit(@RequestBody MinderExtraNodeEditRequest request) { // public void minderEdit(@RequestBody TestCaseMinderEditRequest.MinderExtraNodeEditRequest request) {
minderExtraNodeService.batchEdit(request); // minderExtraNodeService.batchEdit(request);
} // }
@GetMapping("/list/{groupId}/{parentId}") @GetMapping("/list/{groupId}/{parentId}")
public List<MinderExtraNode> list(@PathVariable String groupId, @PathVariable String parentId) { public List<MinderExtraNode> list(@PathVariable String groupId, @PathVariable String parentId) {

View File

@ -4,16 +4,14 @@ import com.alibaba.fastjson.JSONObject;
import io.metersphere.base.domain.MinderExtraNode; import io.metersphere.base.domain.MinderExtraNode;
import io.metersphere.base.domain.MinderExtraNodeExample; import io.metersphere.base.domain.MinderExtraNodeExample;
import io.metersphere.base.mapper.MinderExtraNodeMapper; import io.metersphere.base.mapper.MinderExtraNodeMapper;
import io.metersphere.track.request.MinderExtraNodeEditRequest; import io.metersphere.track.request.testcase.TestCaseMinderEditRequest;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -22,8 +20,9 @@ public class MinderExtraNodeService {
@Resource @Resource
MinderExtraNodeMapper minderExtraNodeMapper; MinderExtraNodeMapper minderExtraNodeMapper;
public void batchEdit(MinderExtraNodeEditRequest request) { public void batchEdit(TestCaseMinderEditRequest request) {
Map<String, List<String>> data = request.getData(); TestCaseMinderEditRequest.MinderExtraNodeEditRequest extraNodeRequest = request.getExtraNodeRequest();
Map<String, List<String>> data = extraNodeRequest.getData();
if (data != null) { if (data != null) {
data.forEach((parentId, nodes) -> { data.forEach((parentId, nodes) -> {
nodes.forEach(node -> { nodes.forEach(node -> {
@ -32,16 +31,14 @@ public class MinderExtraNodeService {
minderExtraNode.setParentId(parentId); minderExtraNode.setParentId(parentId);
JSONObject nodeObj = JSONObject.parseObject(node); JSONObject nodeObj = JSONObject.parseObject(node);
String id = nodeObj.getString("id"); String id = nodeObj.getString("id");
if (StringUtils.isBlank(id) || id.length() < 20) { minderExtraNode.setId(id);
minderExtraNode.setId(UUID.randomUUID().toString()); if (nodeObj.getBoolean("isEdit")) {
minderExtraNode.setGroupId(request.getGroupId()); minderExtraNodeMapper.updateByPrimaryKeySelective(minderExtraNode);
minderExtraNode.setType(request.getType()); } else {
nodeObj.put("id", minderExtraNode.getId()); minderExtraNode.setGroupId(extraNodeRequest.getGroupId());
minderExtraNode.setType(extraNodeRequest.getType());
minderExtraNode.setNodeData(nodeObj.toJSONString()); minderExtraNode.setNodeData(nodeObj.toJSONString());
minderExtraNodeMapper.insert(minderExtraNode); minderExtraNodeMapper.insert(minderExtraNode);
} else {
minderExtraNode.setId(id);
minderExtraNodeMapper.updateByPrimaryKeySelective(minderExtraNode);
} }
}); });
}); });

View File

@ -1,18 +0,0 @@
package io.metersphere.track.request;
import io.metersphere.base.domain.MinderExtraNode;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class MinderExtraNodeEditRequest extends MinderExtraNode {
private String projectId;
// 删除的id
private List<String> ids;
// key 为父节点id
private Map<String, List<String>> data;
}

View File

@ -1,22 +1,42 @@
package io.metersphere.track.request.testcase; package io.metersphere.track.request.testcase;
import io.metersphere.base.domain.MinderExtraNode;
import io.metersphere.base.domain.TestCaseNode;
import io.metersphere.base.domain.TestCaseWithBLOBs; import io.metersphere.base.domain.TestCaseWithBLOBs;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.util.List; import java.util.List;
import java.util.Map;
@Getter @Getter
@Setter @Setter
public class TestCaseMinderEditRequest { public class TestCaseMinderEditRequest {
private String projectId; private String projectId;
private List<String> ids; private List<String> ids;
List<TestCaseMinderEditItem> data; private List<TestCaseMinderEditItem> data;
private List<TestCaseNodeMinderEditItem> testCaseNodes;
private MinderExtraNodeEditRequest extraNodeRequest;
@Getter
@Setter
public static class MinderExtraNodeEditRequest extends MinderExtraNode {
private Map<String, List<String>> data;
}
@Getter @Getter
@Setter @Setter
public static class TestCaseMinderEditItem extends TestCaseWithBLOBs { public static class TestCaseMinderEditItem extends TestCaseWithBLOBs {
private Boolean isEdit;
private String targetId; private String targetId;
private String moveMode; private String moveMode;
} }
@Getter
@Setter
public static class TestCaseNodeMinderEditItem extends TestCaseNode {
private Boolean isEdit;
private List<String> nodeIds;
}
} }

View File

@ -10,6 +10,7 @@ import io.metersphere.base.mapper.ext.ExtTestCaseNodeMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper; import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.commons.constants.TestCaseConstants; import io.metersphere.commons.constants.TestCaseConstants;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.commons.utils.CommonBeanFactory; import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.SessionUtils; import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.dto.NodeNumDTO; import io.metersphere.dto.NodeNumDTO;
@ -23,10 +24,7 @@ import io.metersphere.service.NodeTreeService;
import io.metersphere.track.dto.TestCaseDTO; import io.metersphere.track.dto.TestCaseDTO;
import io.metersphere.track.dto.TestCaseNodeDTO; import io.metersphere.track.dto.TestCaseNodeDTO;
import io.metersphere.track.dto.TestPlanCaseDTO; import io.metersphere.track.dto.TestPlanCaseDTO;
import io.metersphere.track.request.testcase.DragNodeRequest; import io.metersphere.track.request.testcase.*;
import io.metersphere.track.request.testcase.QueryNodeRequest;
import io.metersphere.track.request.testcase.QueryTestCaseRequest;
import io.metersphere.track.request.testcase.TestCaseBatchRequest;
import io.metersphere.track.request.testplancase.QueryTestPlanCaseRequest; import io.metersphere.track.request.testplancase.QueryTestPlanCaseRequest;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ExecutorType;
@ -65,8 +63,6 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
@Resource @Resource
ProjectMapper projectMapper; ProjectMapper projectMapper;
@Resource @Resource
TestCaseReviewService testCaseReviewService;
@Resource
TestCaseReviewTestCaseMapper testCaseReviewTestCaseMapper; TestCaseReviewTestCaseMapper testCaseReviewTestCaseMapper;
@Resource @Resource
TestCaseReviewMapper testCaseReviewMapper; TestCaseReviewMapper testCaseReviewMapper;
@ -79,7 +75,9 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
validateNode(node); validateNode(node);
node.setCreateTime(System.currentTimeMillis()); node.setCreateTime(System.currentTimeMillis());
node.setUpdateTime(System.currentTimeMillis()); node.setUpdateTime(System.currentTimeMillis());
if (StringUtils.isBlank(node.getId())) {
node.setId(UUID.randomUUID().toString()); node.setId(UUID.randomUUID().toString());
}
node.setCreateUser(SessionUtils.getUserId()); node.setCreateUser(SessionUtils.getUserId());
double pos = getNextLevelPos(node.getProjectId(), node.getLevel(), node.getParentId()); double pos = getNextLevelPos(node.getProjectId(), node.getLevel(), node.getParentId());
node.setPos(pos); node.setPos(pos);
@ -91,8 +89,6 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
return extTestCaseNodeMapper.getNodes(nodeId); return extTestCaseNodeMapper.getNodes(nodeId);
} }
;
private void validateNode(TestCaseNode node) { private void validateNode(TestCaseNode node) {
if (node.getLevel() > TestCaseConstants.MAX_NODE_DEPTH) { if (node.getLevel() > TestCaseConstants.MAX_NODE_DEPTH) {
throw new RuntimeException(Translator.get("test_case_node_level_tip") throw new RuntimeException(Translator.get("test_case_node_level_tip")
@ -236,8 +232,8 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
public int editNode(DragNodeRequest request) { public int editNode(DragNodeRequest request) {
request.setUpdateTime(System.currentTimeMillis()); request.setUpdateTime(System.currentTimeMillis());
checkTestCaseNodeExist(request); checkTestCaseNodeExist(request);
if (!CollectionUtils.isEmpty(request.getNodeIds())) {
List<TestCaseDTO> testCases = QueryTestCaseByNodeIds(request.getNodeIds()); List<TestCaseDTO> testCases = QueryTestCaseByNodeIds(request.getNodeIds());
testCases.forEach(testCase -> { testCases.forEach(testCase -> {
StringBuilder path = new StringBuilder(testCase.getNodePath()); StringBuilder path = new StringBuilder(testCase.getNodePath());
List<String> pathLists = Arrays.asList(path.toString().split("/")); List<String> pathLists = Arrays.asList(path.toString().split("/"));
@ -248,13 +244,15 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
} }
testCase.setNodePath(path.toString()); testCase.setNodePath(path.toString());
}); });
batchUpdateTestCase(testCases); batchUpdateTestCase(testCases);
}
return testCaseNodeMapper.updateByPrimaryKeySelective(request); return testCaseNodeMapper.updateByPrimaryKeySelective(request);
} }
public int deleteNode(List<String> nodeIds) { public int deleteNode(List<String> nodeIds) {
if (CollectionUtils.isEmpty(nodeIds)) {
return 1;
}
TestCaseService testCaseService = CommonBeanFactory.getBean(TestCaseService.class); TestCaseService testCaseService = CommonBeanFactory.getBean(TestCaseService.class);
List<String> testCaseIdList = this.selectCaseIdByNodeIds(nodeIds); List<String> testCaseIdList = this.selectCaseIdByNodeIds(nodeIds);
TestCaseBatchRequest request = new TestCaseBatchRequest(); TestCaseBatchRequest request = new TestCaseBatchRequest();
@ -770,4 +768,29 @@ public class TestCaseNodeService extends NodeTreeService<TestCaseNodeDTO> {
testCaseExample.createCriteria().andProjectIdEqualTo(projectId).andStatusEqualTo("Trash"); testCaseExample.createCriteria().andProjectIdEqualTo(projectId).andStatusEqualTo("Trash");
return testCaseMapper.countByExample(testCaseExample); return testCaseMapper.countByExample(testCaseExample);
} }
public void minderEdit(TestCaseMinderEditRequest request) {
deleteNode(request.getIds());
List<TestCaseMinderEditRequest.TestCaseNodeMinderEditItem> testCaseNodes = request.getTestCaseNodes();
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(testCaseNodes)) {
for (TestCaseMinderEditRequest.TestCaseNodeMinderEditItem item: testCaseNodes) {
if (StringUtils.isBlank(item.getParentId()) || item.getParentId().equals("root")) {
item.setParentId("");
}
item.setProjectId(request.getProjectId());
if (item.getIsEdit()) {
DragNodeRequest editNode = new DragNodeRequest();
BeanUtils.copyBean(editNode, item);
editNode(editNode);
} else {
TestCaseNode testCaseNode = new TestCaseNode();
BeanUtils.copyBean(testCaseNode, item);
testCaseNode.setProjectId(request.getProjectId());
addNode(testCaseNode);
}
}
}
}
} }

View File

@ -145,6 +145,8 @@ public class TestCaseService {
@Resource @Resource
@Lazy @Lazy
private TestPlanService testPlanService; private TestPlanService testPlanService;
@Resource
private MinderExtraNodeService minderExtraNodeService;
private void setNode(TestCaseWithBLOBs testCase) { private void setNode(TestCaseWithBLOBs testCase) {
if (StringUtils.isEmpty(testCase.getNodeId()) || "default-module".equals(testCase.getNodeId())) { if (StringUtils.isEmpty(testCase.getNodeId()) || "default-module".equals(testCase.getNodeId())) {
@ -1480,10 +1482,15 @@ public class TestCaseService {
} }
public void minderEdit(TestCaseMinderEditRequest request) { public void minderEdit(TestCaseMinderEditRequest request) {
deleteToGcBatch(request.getIds());
testCaseNodeService.minderEdit(request);
List<TestCaseMinderEditRequest.TestCaseMinderEditItem> data = request.getData(); List<TestCaseMinderEditRequest.TestCaseMinderEditItem> data = request.getData();
if (CollectionUtils.isNotEmpty(data)) { if (CollectionUtils.isNotEmpty(data)) {
List<String> editIds = data.stream() List<String> editIds = data.stream()
.filter(t -> StringUtils.isNotBlank(t.getId()) && t.getId().length() > 20) .filter(TestCaseMinderEditRequest.TestCaseMinderEditItem::getIsEdit)
.map(TestCaseWithBLOBs::getId).collect(Collectors.toList()); .map(TestCaseWithBLOBs::getId).collect(Collectors.toList());
Map<String, TestCaseWithBLOBs> testCaseMap = new HashMap<>(); Map<String, TestCaseWithBLOBs> testCaseMap = new HashMap<>();
@ -1494,31 +1501,29 @@ public class TestCaseService {
testCaseMap = testCaseWithBLOBs.stream().collect(Collectors.toMap(TestCaseWithBLOBs::getId, t -> t)); testCaseMap = testCaseWithBLOBs.stream().collect(Collectors.toMap(TestCaseWithBLOBs::getId, t -> t));
} }
Map<String, TestCaseWithBLOBs> finalTestCaseMap = testCaseMap; for (TestCaseMinderEditRequest.TestCaseMinderEditItem item: data) {
data.forEach(item -> {
if (StringUtils.isBlank(item.getNodeId()) || item.getNodeId().equals("root")) { if (StringUtils.isBlank(item.getNodeId()) || item.getNodeId().equals("root")) {
item.setNodeId(""); item.setNodeId("");
} }
item.setProjectId(request.getProjectId()); item.setProjectId(request.getProjectId());
if (StringUtils.isBlank(item.getId()) || item.getId().length() < 20) { if (item.getIsEdit()) {
item.setId(UUID.randomUUID().toString()); TestCaseWithBLOBs dbCase = testCaseMap.get(item.getId());
item.setMaintainer(SessionUtils.getUserId());
EditTestCaseRequest editTestCaseRequest = new EditTestCaseRequest();
BeanUtils.copyBean(editTestCaseRequest, item);
addTestCase(editTestCaseRequest);
changeOrder(item, request.getProjectId());
} else {
TestCaseWithBLOBs dbCase = finalTestCaseMap.get(item.getId());
if (editCustomFieldsPriority(dbCase, item.getPriority())) { if (editCustomFieldsPriority(dbCase, item.getPriority())) {
item.setCustomFields(dbCase.getCustomFields()); item.setCustomFields(dbCase.getCustomFields());
} }
editTestCase(item); editTestCase(item);
changeOrder(item, request.getProjectId()); changeOrder(item, request.getProjectId());
} else {
item.setMaintainer(SessionUtils.getUserId());
EditTestCaseRequest editTestCaseRequest = new EditTestCaseRequest();
BeanUtils.copyBean(editTestCaseRequest, item);
addTestCase(editTestCaseRequest);
changeOrder(item, request.getProjectId());
} }
});
} }
List<String> ids = request.getIds(); }
deleteToGcBatch(ids);
minderExtraNodeService.batchEdit(request);
} }
private void changeOrder(TestCaseMinderEditRequest.TestCaseMinderEditItem item, String projectId) { private void changeOrder(TestCaseMinderEditRequest.TestCaseMinderEditItem item, String projectId) {

View File

@ -268,9 +268,9 @@ public class TestPlanReportService {
// testPlanReport.setPrincipal(testPlan.getPrincipal()); // testPlanReport.setPrincipal(testPlan.getPrincipal());
if (testPlanReport.getIsScenarioExecuting() || testPlanReport.getIsApiCaseExecuting() || testPlanReport.getIsPerformanceExecuting()) { if (testPlanReport.getIsScenarioExecuting() || testPlanReport.getIsApiCaseExecuting() || testPlanReport.getIsPerformanceExecuting()) {
testPlanReport.setStatus(APITestStatus.Running.name()); testPlanReport.setStatus(TestPlanReportStatus.RUNNING.name());
} else { } else {
testPlanReport.setStatus(APITestStatus.Completed.name()); testPlanReport.setStatus(TestPlanReportStatus.COMPLETED.name());
} }
testPlanReportMapper.insert(testPlanReport); testPlanReportMapper.insert(testPlanReport);

View File

@ -54,7 +54,7 @@
"vue-float-action-button": "^0.6.6", "vue-float-action-button": "^0.6.6",
"vue-i18n": "^8.15.3", "vue-i18n": "^8.15.3",
"vue-jsonpath-picker": "^1.1.5", "vue-jsonpath-picker": "^1.1.5",
"vue-minder-editor-plus": "1.0.30", "vue-minder-editor-plus": "1.0.33",
"vue-papa-parse": "^2.0.0", "vue-papa-parse": "^2.0.0",
"vue-pdf": "^4.2.0", "vue-pdf": "^4.2.0",
"vue-router": "^3.1.3", "vue-router": "^3.1.3",

View File

@ -69,7 +69,13 @@ export default {
priorityDisableCheck: Function, priorityDisableCheck: Function,
disabled: Boolean, disabled: Boolean,
ignoreNum: Boolean, ignoreNum: Boolean,
showModuleTag: Boolean showModuleTag: Boolean,
moduleDisable: {
type: Boolean,
default() {
return true;
}
}
}, },
data() { data() {
return { return {
@ -80,6 +86,7 @@ export default {
disable: true, disable: true,
id: "root", id: "root",
type: 'node', type: 'node',
level: 0,
resource: this.showModuleTag ? ['模块'] : [], resource: this.showModuleTag ? ['模块'] : [],
path: "", path: "",
tagEnable: this.tagEnable tagEnable: this.tagEnable
@ -150,8 +157,9 @@ export default {
data: { data: {
text: item.name, text: item.name,
id: item.id, id: item.id,
disable: true, disable: this.moduleDisable,
type: 'node', type: 'node',
level: item.level,
resource: this.showModuleTag ? ['模块'] : [], resource: this.showModuleTag ? ['模块'] : [],
caseNum: item.caseNum, caseNum: item.caseNum,
path: root.data.path + "/" + item.name, path: root.data.path + "/" + item.name,
@ -206,9 +214,10 @@ export default {
data: { data: {
text: nodeData.name, text: nodeData.name,
id: nodeData.id, id: nodeData.id,
disable: true, disable: this.moduleDisable,
tagEnable: this.tagEnable, tagEnable: this.tagEnable,
type: 'node', type: 'node',
level: nodeData.level,
resource: this.showModuleTag ? ['模块'] : [], resource: this.showModuleTag ? ['模块'] : [],
}, },
children: [] children: []

View File

@ -6,6 +6,7 @@
minder-key="testCase" minder-key="testCase"
:select-node="selectNode" :select-node="selectNode"
:distinct-tags="tags" :distinct-tags="tags"
:module-disable="false"
:show-module-tag="true" :show-module-tag="true"
:tag-edit-check="tagEditCheck()" :tag-edit-check="tagEditCheck()"
@afterMount="handleAfterMount" @afterMount="handleAfterMount"
@ -19,6 +20,7 @@
<script> <script>
import MsModuleMinder from "@/business/components/common/components/MsModuleMinder"; import MsModuleMinder from "@/business/components/common/components/MsModuleMinder";
import { import {
getChildNodeId,
handleAfterSave, handleAfterSave,
handleExpandToLevel, handleTestCaseAdd, handTestCaeEdit, handleExpandToLevel, handleTestCaseAdd, handTestCaeEdit,
listenBeforeExecCommand, listenDblclick, listenBeforeExecCommand, listenDblclick,
@ -27,7 +29,7 @@ import {
priorityDisableCheck, priorityDisableCheck,
tagEditCheck, tagEditCheck,
} from "@/business/components/track/common/minder/minderUtils"; } from "@/business/components/track/common/minder/minderUtils";
import {getNodePath, hasPermission} from "@/common/js/utils"; import {getNodePath, getUUID, hasPermission} from "@/common/js/utils";
import {getTestCasesForMinder, getMinderExtraNode} from "@/network/testCase"; import {getTestCasesForMinder, getMinderExtraNode} from "@/network/testCase";
export default { export default {
name: "TestCaseMinder", name: "TestCaseMinder",
@ -36,9 +38,14 @@ name: "TestCaseMinder",
return{ return{
testCase: [], testCase: [],
dataMap: new Map(), dataMap: new Map(),
tags: [this.$t('api_test.definition.request.case'), this.$t('test_track.case.prerequisite'), this.$t('commons.remark'), '模块'], tags: [this.$t('api_test.definition.request.case'), this.$t('test_track.case.prerequisite'), this.$t('commons.remark'), this.$t('test_track.module.module')],
result: {loading: false}, result: {loading: false},
needRefresh: false, needRefresh: false,
saveCases: [],
saveModules: [],
saveModuleNodeMap: new Map(),
deleteNodes: [], //
saveExtraNode: {}
} }
}, },
props: { props: {
@ -127,72 +134,59 @@ name: "TestCaseMinder",
setIsChange(isChanged) { setIsChange(isChanged) {
this.$store.commit('setIsTestCaseMinderChanged', isChanged); this.$store.commit('setIsTestCaseMinderChanged', isChanged);
}, },
save(data) { save() {
let saveCases = []; this.saveCases = [];
let deleteCases = []; // this.saveModules = [];
let saveExtraNode = {}; this.deleteNodes = []; //
this.buildSaveCase(data.root, saveCases, deleteCases, saveExtraNode); this.saveExtraNode = {};
this.saveModuleNodeMap = new Map();
this.buildSaveParam(window.minder.getRoot());
this.saveModules.forEach(module => {
let nodeIds = [];
getChildNodeId(this.saveModuleNodeMap.get(module.id), nodeIds);
module.nodeIds = nodeIds;
});
let param = { let param = {
projectId: this.projectId, projectId: this.projectId,
data: saveCases, data: this.saveCases,
ids: deleteCases.map(item => item.id) ids: this.deleteNodes.map(item => item.id),
} testCaseNodes: this.saveModules,
extraNodeRequest: {
let saveCase = new Promise((resolve) => {
this.result = this.$post('/test/case/minder/edit', param, () => {
resolve();
});
});
let extraNodeParam = {
groupId: this.projectId, groupId: this.projectId,
type: "TEST_CASE", type: "TEST_CASE",
data: saveExtraNode, data: this.saveExtraNode,
ids: deleteCases.map(item => item.id) }
} }
let saveExtraNodePromise = new Promise((resolve) => { this.result = this.$post('/test/case/minder/edit', param, () => {
this.result = this.$post('/minder/extra/node/batch/edit', extraNodeParam, () => {
resolve();
});
});
Promise.all([saveCase, saveExtraNodePromise])
.then(() => {
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
handleAfterSave(window.minder.getRoot(), this.getParam()); handleAfterSave(window.minder.getRoot());
this.$emit('refresh'); this.$emit('refresh');
this.setIsChange(false); this.setIsChange(false);
}); });
}, },
buildSaveCase(root, saveCases, deleteCases, saveExtraNode, parent, preNode, nextNode) { buildSaveParam(root, parent, preNode, nextNode) {
let data = root.data; let data = root.data;
if (data.resource && data.resource.indexOf(this.$t('api_test.definition.request.case')) > -1) { if (data.resource && data.resource.indexOf(this.$t('api_test.definition.request.case')) > -1) {
this._buildSaveCase(root, saveCases, deleteCases, parent, preNode, nextNode); this.buildSaveCase(root, parent, preNode, nextNode);
} else { } else {
let deleteChild = data.deleteChild; let deleteChild = data.deleteChild;
if (deleteChild && deleteChild.length > 0 && data.type === 'node') { if (deleteChild && deleteChild.length > 0 && data.type === 'node') {
deleteCases.push(...deleteChild); this.deleteNodes.push(...deleteChild);
} }
if (data.type !== 'node' && data.type !== 'tmp' if (data.type !== 'tmp' && data.changed) {
&& parent && parent.type === 'node' && data.changed === true) { if (data.contextChanged && data.resource && data.resource.indexOf(this.$t('test_track.module.module')) > -1) {
// this.buildSaveModules(root, data, parent);
let nodes = saveExtraNode[parent.id]; } else {
if (!nodes) { //
nodes = []; this.buildExtraNode(data, parent, root);
} }
nodes.push(JSON.stringify(this.buildExtraNode(root)));
saveExtraNode[parent.id] = nodes;
} }
if (data.id === null) {
let tip = '脑图编辑无法创建模块:' + data.text + '';
this.$error(tip)
throw new Error(tip);
}
if (root.children) { if (root.children) {
for (let i = 0; i < root.children.length; i++) { for (let i = 0; i < root.children.length; i++) {
let childNode = root.children[i]; let childNode = root.children[i];
@ -204,12 +198,60 @@ name: "TestCaseMinder",
if (i + 1 < root.children.length) { if (i + 1 < root.children.length) {
nextNode = root.children[i + 1]; nextNode = root.children[i + 1];
} }
this.buildSaveCase(childNode, saveCases, deleteCases, saveExtraNode, root.data, preNode, nextNode); this.buildSaveParam(childNode, root.data, preNode, nextNode);
} }
} }
} }
}, },
_buildSaveCase(node, saveCases, deleteCases, parent, preNode, nextNode) { buildSaveModules(node, data, parent) {
if (!data.text) {
return;
}
let pId = parent ? (parent.newId ? parent.newId : parent.id) : null;
let module = {
id: data.id,
name: data.text,
level: data.level ? data.level : (parent.level + 1),
parentId: pId
};
data.level = module.level;
if (data.isExtraNode) {
//
this.pushDeleteNode(data);
}
if (data.type === 'case') {
//
this.pushDeleteNode(data);
}
if (module.id && module.id.length > 20) {
module.isEdit = true; //
} else {
module.isEdit = false; //
module.id = getUUID();
data.newId = module.id;
this.moduleOptions.push({id: data.newId, path: getNodePath(pId, this.moduleOptions) + '/' + module.name});
}
this.saveModuleNodeMap.set(module.id, node);
this.saveModules.push(module);
},
buildExtraNode(data, parent, root) {
if (data.type !== 'node' && data.type !== 'tmp'
&& parent && parent.type === 'node' && data.changed === true) {
//
let nodes = this.saveExtraNode[parent.id];
if (!nodes) {
nodes = [];
}
nodes.push(JSON.stringify(this._buildExtraNode(root)));
this.saveExtraNode[parent.id] = nodes;
}
},
buildSaveCase(node, parent, preNode, nextNode) {
let data = node.data; let data = node.data;
if (!data.text) { if (!data.text) {
return; return;
@ -221,20 +263,25 @@ name: "TestCaseMinder",
throw new Error(tip); throw new Error(tip);
} }
if (data.type === 'node') {
let tip = data.text + '是模块,不能修改为用例';
this.$error(tip)
throw new Error(tip);
}
if (data.isExtraNode) { if (data.isExtraNode) {
// //
let deleteData = {}; this.pushDeleteNode(data);
Object.assign(deleteData, data);
deleteCases.push(deleteData);
data.id = "";
} }
let isChange = false; let isChange = false;
let nodeId = parent ? (parent.newId ? parent.newId : parent.id) : "";
let testCase = { let testCase = {
id: data.id, id: data.id,
name: data.text, name: data.text,
nodeId: parent ? parent.id : "", nodeId: nodeId,
nodePath: getNodePath(parent ? parent.id : '', this.moduleOptions), nodePath: getNodePath(nodeId, this.moduleOptions),
type: data.type ? data.type : 'functional', type: data.type ? data.type : 'functional',
method: data.method ? data.method: 'manual', method: data.method ? data.method: 'manual',
maintainer: data.maintainer, maintainer: data.maintainer,
@ -297,7 +344,14 @@ name: "TestCaseMinder",
} }
} }
saveCases.push(testCase); if (testCase.id && testCase.id.length > 20) {
testCase.isEdit = true; //
} else {
testCase.isEdit = false; //
testCase.id = getUUID();
data.newId = testCase.id;
}
this.saveCases.push(testCase);
} }
if (testCase.nodeId !== 'root' && testCase.nodeId.length < 15) { if (testCase.nodeId !== 'root' && testCase.nodeId.length < 15) {
let tip = this.$t('test_track.case.create_case') + "'" + testCase.name + "'" + this.$t('test_track.case.minder_create_tip'); let tip = this.$t('test_track.case.create_case') + "'" + testCase.name + "'" + this.$t('test_track.case.minder_create_tip');
@ -305,23 +359,37 @@ name: "TestCaseMinder",
throw new Error(tip); throw new Error(tip);
} }
}, },
pushDeleteNode(data) {
//
let deleteData = {};
Object.assign(deleteData, data);
this.deleteNodes.push(deleteData);
data.id = "";
},
isCaseNode(node) { isCaseNode(node) {
if (node && node.resource && node.resource.indexOf(this.$t('api_test.definition.request.case')) > -1) { if (node && node.resource && node.resource.indexOf(this.$t('api_test.definition.request.case')) > -1) {
return true; return true;
} }
return false; return false;
}, },
buildExtraNode(node) { _buildExtraNode(node) {
let data = node.data; let data = node.data;
let nodeData = { let nodeData = {
text: data.text, text: data.text,
id: data.id, id: data.id,
resource: data.resource, resource: data.resource,
}; };
if (nodeData.id && nodeData.id.length > 20) {
nodeData.isEdit = true; //
} else {
nodeData.isEdit = false; //
nodeData.id = getUUID();
data.newId = nodeData.id;
}
if (node.children) { if (node.children) {
nodeData.children = []; nodeData.children = [];
node.children.forEach(item => { node.children.forEach(item => {
nodeData.children.push(this.buildExtraNode(item)); nodeData.children.push(this._buildExtraNode(item));
}); });
} }
return nodeData; return nodeData;

View File

@ -180,7 +180,7 @@ export function appendCase(parent, item, isDisable, setParamCallback) {
text: item.name, text: item.name,
priority: Number.parseInt(item.priority.substring(item.priority.length - 1 )) + 1, priority: Number.parseInt(item.priority.substring(item.priority.length - 1 )) + 1,
resource: [i18n.t('api_test.definition.request.case')], resource: [i18n.t('api_test.definition.request.case')],
type: item.type, type: 'case',
method: item.method, method: item.method,
maintainer: item.maintainer, maintainer: item.maintainer,
stepModel: item.stepModel stepModel: item.stepModel
@ -356,16 +356,25 @@ export function tagBatch(distinctTags) {
}); });
} }
function parentIsModule(parentNode) {
let lastNodeResource = parentNode ? parentNode.data.resource : null;
return parentNode.data.type === 'node' || (lastNodeResource && lastNodeResource.indexOf('模块') > -1);
}
export function tagEditCheck(resourceName) { export function tagEditCheck(resourceName) {
let minder = window.minder; let minder = window.minder;
let selectNodes = minder.getSelectedNodes(); let selectNodes = minder.getSelectedNodes();
if (selectNodes && selectNodes.length > 0) { if (selectNodes && selectNodes.length > 0) {
let lastNodeResource = selectNodes[0].getParent().data.resource; let type = selectNodes[0].data.type;
if ( resourceName === '模块') { if (type === 'case' || type === 'node') {// 已存在的模块和用例不能修改标签
// 模块不能编辑
return false; return false;
} }
if (lastNodeResource && lastNodeResource.indexOf('用例') > -1 && resourceName === '用例') { let parentIsModuleNode = parentIsModule(selectNodes[0].getParent());
if (resourceName === '用例' && !parentIsModuleNode) {
return false;
}
// 父节点必须是模块
if (resourceName === '模块' && !parentIsModuleNode) {
return false; return false;
} }
} }
@ -377,7 +386,8 @@ export function priorityDisableCheck() {
let minder = window.minder; let minder = window.minder;
let selectNodes = minder.getSelectedNodes(); let selectNodes = minder.getSelectedNodes();
if (selectNodes && selectNodes.length > 0) { if (selectNodes && selectNodes.length > 0) {
let resource = selectNodes[0].getParent().data.resource; let parentNode = selectNodes[0].getParent();
let resource = parentNode ? parentNode.data.resource : null;
if (resource && resource.indexOf('用例') > -1) { if (resource && resource.indexOf('用例') > -1) {
return true; return true;
} }
@ -385,22 +395,32 @@ export function priorityDisableCheck() {
return false; return false;
} }
export function handleAfterSave(pNode, param) { export function handleAfterSave(rootNode) {
let children = pNode.children; if (rootNode.data.newId) {
if (children) { rootNode.data.id = rootNode.data.newId;
for (let i = 0; i < children.length; i++) { rootNode.data.newId = null;
let item = children[i];
if (item.data.id === null || (item.data.id && item.data.id.length < 20)) {
pNode.data.loaded = false;
loadNode(pNode, param, getTestCasesForMinder, null, getMinderExtraNode);
return;
} }
if (item.data.changed) { rootNode.data.deleteChild = null;
item.data.changed = false; rootNode.data.changed = false;
} if (rootNode.children) {
if (item.data.type === 'node') { for (let i = 0; i < rootNode.children.length; i++) {
handleAfterSave(item, param); handleAfterSave(rootNode.children[i]);
} }
} }
} }
export function getChildNodeId(rootNode, nodeIds) {
//递归获取所有子节点ID
if (rootNode.data.id) {
if (rootNode.data.newId) {
nodeIds.push(rootNode.data.newId);
} else {
nodeIds.push(rootNode.data.id);
}
}
if (rootNode.children) {
for (let i = 0; i < rootNode.children.length; i++) {
getChildNodeId(rootNode.children[i], nodeIds);
}
}
} }