feat: 脑图支持创建缺陷

This commit is contained in:
AnAngle 2021-11-21 22:13:16 +08:00 committed by jianxing
parent 3b099091ab
commit 5ccbc15b5f
30 changed files with 278 additions and 77 deletions

View File

@ -14,5 +14,6 @@ public class IssuesDao extends IssuesWithBLOBs {
private String resourceName; private String resourceName;
private long caseCount; private long caseCount;
private List<String> caseIds; private List<String> caseIds;
private String caseId;
private int totalIssueCount; private int totalIssueCount;
} }

View File

@ -12,6 +12,8 @@ public interface ExtIssuesMapper {
List<IssuesDao> getIssuesByCaseId(@Param("request") IssuesRequest issuesRequest); List<IssuesDao> getIssuesByCaseId(@Param("request") IssuesRequest issuesRequest);
List<IssuesDao> getIssueForMinder(@Param("caseIds") List<String> caseIds);
List<IssuesDao> getIssues(@Param("request") IssuesRequest issuesRequest); List<IssuesDao> getIssues(@Param("request") IssuesRequest issuesRequest);
List<IssuesDao> getRelateIssues(@Param("request") IssuesRequest request); List<IssuesDao> getRelateIssues(@Param("request") IssuesRequest request);

View File

@ -16,6 +16,19 @@
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/> <include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select> </select>
<select id="getIssueForMinder" resultType="io.metersphere.base.domain.IssuesDao">
select issues.id, issues.title , issues.num , test_case_issues.test_case_id as caseId
from issues
inner join test_case_issues
on test_case_issues.issues_id = issues.id
where test_case_id in
<foreach collection="caseIds" open="(" close=")" item="item">
#{item}
</foreach>
and (issues.platform_status != 'delete' or issues.platform_status is NULL)
order by num asc
</select>
<select id="getIssues" resultType="io.metersphere.base.domain.IssuesDao"> <select id="getIssues" resultType="io.metersphere.base.domain.IssuesDao">
select issues.id, issues.platform_id, issues.num, ifnull(issues.title, '') as title, issues.project_id, issues.create_time, issues.update_time, select issues.id, issues.platform_id, issues.num, ifnull(issues.title, '') as title, issues.project_id, issues.create_time, issues.update_time,
ifnull(issues.description, '') as description, issues.status, issues.platform, issues.custom_fields, issues.reporter, ifnull(issues.description, '') as description, issues.status, issues.platform, issues.custom_fields, issues.reporter,

View File

@ -91,7 +91,7 @@ public interface ExtTestCaseMapper {
int getTestPlanPassCase(@Param("planId") String planId); int getTestPlanPassCase(@Param("planId") String planId);
List<TestCaseWithBLOBs> listForMinder(@Param("request") QueryTestCaseRequest request); List<TestCaseDTO> listForMinder(@Param("request") QueryTestCaseRequest request);
List<TestCaseDTO> getTestCaseByIds(@Param("ids")List<String> ids); List<TestCaseDTO> getTestCaseByIds(@Param("ids")List<String> ids);

View File

@ -492,7 +492,7 @@
) as temp ) as temp
</select> </select>
<select id="listForMinder" resultType="io.metersphere.base.domain.TestCaseWithBLOBs"> <select id="listForMinder" resultType="io.metersphere.track.dto.TestCaseDTO">
select select
<include refid="io.metersphere.base.mapper.TestCaseMapper.Base_Column_List"/>, <include refid="io.metersphere.base.mapper.TestCaseMapper.Base_Column_List"/>,
<include refid="io.metersphere.base.mapper.TestCaseMapper.Blob_Column_List"/> <include refid="io.metersphere.base.mapper.TestCaseMapper.Blob_Column_List"/>

View File

@ -448,6 +448,7 @@
t.type, t.node_id, t.type, t.node_id,
t.steps, t.prerequisite, t.steps, t.prerequisite,
t.remark, t.remark,
t.id as caseId,
t.node_path, t.method, t.num, t.step_model, t.expected_result, t.step_description t.node_path, t.method, t.num, t.step_model, t.expected_result, t.step_description
from test_plan_test_case pc from test_plan_test_case pc
inner join test_case t on pc.case_id = t.id inner join test_case t on pc.case_id = t.id

View File

@ -4,6 +4,7 @@ import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.Issues; import io.metersphere.base.domain.Issues;
import io.metersphere.base.domain.IssuesDao; import io.metersphere.base.domain.IssuesDao;
import io.metersphere.base.domain.IssuesWithBLOBs;
import io.metersphere.commons.constants.NoticeConstants; import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants; import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.utils.PageUtils; import io.metersphere.commons.utils.PageUtils;
@ -44,8 +45,8 @@ public class IssuesController {
@MsAuditLog(module = "track_bug", type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#issuesRequest)", msClass = IssuesService.class) @MsAuditLog(module = "track_bug", type = OperLogConstants.CREATE, content = "#msClass.getLogDetails(#issuesRequest)", msClass = IssuesService.class)
@SendNotice(taskType = NoticeConstants.TaskType.DEFECT_TASK, target = "#issuesRequest", @SendNotice(taskType = NoticeConstants.TaskType.DEFECT_TASK, target = "#issuesRequest",
event = NoticeConstants.Event.CREATE, mailTemplate = "track/IssuesCreate", subject = "缺陷通知") event = NoticeConstants.Event.CREATE, mailTemplate = "track/IssuesCreate", subject = "缺陷通知")
public void addIssues(@RequestBody IssuesUpdateRequest issuesRequest) { public IssuesWithBLOBs addIssues(@RequestBody IssuesUpdateRequest issuesRequest) {
issuesService.addIssues(issuesRequest); return issuesService.addIssues(issuesRequest);
} }
@PostMapping("/update") @PostMapping("/update")

View File

@ -82,7 +82,7 @@ public class TestCaseController {
} }
@PostMapping("/list/minder") @PostMapping("/list/minder")
public List<TestCaseWithBLOBs> listDetail(@RequestBody QueryTestCaseRequest request) { public List<TestCaseDTO> listDetail(@RequestBody QueryTestCaseRequest request) {
checkPermissionService.checkProjectOwner(request.getProjectId()); checkPermissionService.checkProjectOwner(request.getProjectId());
return testCaseService.listTestCaseForMinder(request); return testCaseService.listTestCaseForMinder(request);
} }

View File

@ -1,5 +1,6 @@
package io.metersphere.track.dto; package io.metersphere.track.dto;
import io.metersphere.base.domain.IssuesDao;
import io.metersphere.base.domain.TestCaseWithBLOBs; import io.metersphere.base.domain.TestCaseWithBLOBs;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -19,4 +20,5 @@ public class TestCaseDTO extends TestCaseWithBLOBs {
private String createName; private String createName;
private List<String> caseTags = new ArrayList<>(); private List<String> caseTags = new ArrayList<>();
private List<IssuesDao> issueList = new ArrayList<>();
} }

View File

@ -1,5 +1,6 @@
package io.metersphere.track.dto; package io.metersphere.track.dto;
import io.metersphere.base.domain.IssuesDao;
import io.metersphere.base.domain.TestCaseWithBLOBs; import io.metersphere.base.domain.TestCaseWithBLOBs;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@ -25,4 +26,5 @@ public class TestPlanCaseDTO extends TestCaseWithBLOBs {
private int issuesCount; private int issuesCount;
private List<TestCaseTestDTO> list; private List<TestCaseTestDTO> list;
private List<IssuesDao> issueList;
} }

View File

@ -197,7 +197,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
issuesMapper.insert(issues); issuesMapper.insert(issues);
} }
protected void insertIssues(IssuesUpdateRequest issuesRequest) { protected IssuesWithBLOBs insertIssues(IssuesUpdateRequest issuesRequest) {
IssuesWithBLOBs issues = new IssuesWithBLOBs(); IssuesWithBLOBs issues = new IssuesWithBLOBs();
BeanUtils.copyBean(issues, issuesRequest); BeanUtils.copyBean(issues, issuesRequest);
issues.setId(issuesRequest.getId()); issues.setId(issuesRequest.getId());
@ -207,6 +207,7 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
issues.setNum(getNextNum(issuesRequest.getProjectId())); issues.setNum(getNextNum(issuesRequest.getProjectId()));
issues.setPlatformStatus(issuesRequest.getPlatformStatus()); issues.setPlatformStatus(issuesRequest.getPlatformStatus());
issuesMapper.insert(issues); issuesMapper.insert(issues);
return issues;
} }
protected int getNextNum(String projectId) { protected int getNextNum(String projectId) {

View File

@ -1,6 +1,7 @@
package io.metersphere.track.issue; package io.metersphere.track.issue;
import io.metersphere.base.domain.IssuesDao; import io.metersphere.base.domain.IssuesDao;
import io.metersphere.base.domain.IssuesWithBLOBs;
import io.metersphere.base.domain.Project; import io.metersphere.base.domain.Project;
import io.metersphere.dto.UserDTO; import io.metersphere.dto.UserDTO;
import io.metersphere.track.dto.DemandDTO; import io.metersphere.track.dto.DemandDTO;
@ -27,7 +28,7 @@ public interface IssuesPlatform {
* *
* @param issuesRequest issueRequest * @param issuesRequest issueRequest
*/ */
void addIssue(IssuesUpdateRequest issuesRequest); IssuesWithBLOBs addIssue(IssuesUpdateRequest issuesRequest);
/** /**
* 更新缺陷 * 更新缺陷

View File

@ -139,7 +139,7 @@ public class JiraPlatform extends AbstractIssuePlatform {
} }
@Override @Override
public void addIssue(IssuesUpdateRequest issuesRequest) { public IssuesWithBLOBs addIssue(IssuesUpdateRequest issuesRequest) {
JiraConfig jiraConfig = setUserConfig(); JiraConfig jiraConfig = setUserConfig();
JSONObject addJiraIssueParam = buildUpdateParam(issuesRequest, jiraConfig.getIssuetype()); JSONObject addJiraIssueParam = buildUpdateParam(issuesRequest, jiraConfig.getIssuetype());
@ -160,10 +160,12 @@ public class JiraPlatform extends AbstractIssuePlatform {
issuesRequest.setId(UUID.randomUUID().toString()); issuesRequest.setId(UUID.randomUUID().toString());
// 插入缺陷表 // 插入缺陷表
insertIssues(issuesRequest); IssuesWithBLOBs res = insertIssues(issuesRequest);
// 用例与第三方缺陷平台中的缺陷关联 // 用例与第三方缺陷平台中的缺陷关联
handleTestCaseIssues(issuesRequest); handleTestCaseIssues(issuesRequest);
return res;
} }
private JSONObject buildUpdateParam(IssuesUpdateRequest issuesRequest, String issuetypeStr) { private JSONObject buildUpdateParam(IssuesUpdateRequest issuesRequest, String issuetypeStr) {

View File

@ -40,7 +40,7 @@ public class LocalPlatform extends LocalAbstractPlatform {
} }
@Override @Override
public void addIssue(IssuesUpdateRequest issuesRequest) { public IssuesWithBLOBs addIssue(IssuesUpdateRequest issuesRequest) {
String issueStatus = "new"; String issueStatus = "new";
if (StringUtils.isNotBlank(issuesRequest.getCustomFields())) { if (StringUtils.isNotBlank(issuesRequest.getCustomFields())) {
List<TestCaseBatchRequest.CustomFiledRequest> fields = JSONObject.parseArray(issuesRequest.getCustomFields(), TestCaseBatchRequest.CustomFiledRequest.class); List<TestCaseBatchRequest.CustomFiledRequest> fields = JSONObject.parseArray(issuesRequest.getCustomFields(), TestCaseBatchRequest.CustomFiledRequest.class);
@ -67,6 +67,8 @@ public class LocalPlatform extends LocalAbstractPlatform {
issuesRequest.setId(id); issuesRequest.setId(id);
handleTestCaseIssues(issuesRequest); handleTestCaseIssues(issuesRequest);
return issues;
} }
@Override @Override

View File

@ -71,7 +71,7 @@ public class TapdPlatform extends AbstractIssuePlatform {
} }
@Override @Override
public void addIssue(IssuesUpdateRequest issuesRequest) { public IssuesWithBLOBs addIssue(IssuesUpdateRequest issuesRequest) {
MultiValueMap<String, Object> param = buildUpdateParam(issuesRequest); MultiValueMap<String, Object> param = buildUpdateParam(issuesRequest);
TapdBug bug = tapdClient.addIssue(param); TapdBug bug = tapdClient.addIssue(param);
@ -82,10 +82,12 @@ public class TapdPlatform extends AbstractIssuePlatform {
issuesRequest.setId(UUID.randomUUID().toString()); issuesRequest.setId(UUID.randomUUID().toString());
// 插入缺陷表 // 插入缺陷表
insertIssues(issuesRequest); IssuesWithBLOBs issues = insertIssues(issuesRequest);
// 用例与第三方缺陷平台中的缺陷关联 // 用例与第三方缺陷平台中的缺陷关联
handleTestCaseIssues(issuesRequest); handleTestCaseIssues(issuesRequest);
return issues;
} }
@Override @Override

View File

@ -153,13 +153,15 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
} }
@Override @Override
public void addIssue(IssuesUpdateRequest issuesRequest) { public IssuesWithBLOBs addIssue(IssuesUpdateRequest issuesRequest) {
setUserConfig(); setUserConfig();
MultiValueMap<String, Object> param = buildUpdateParam(issuesRequest); MultiValueMap<String, Object> param = buildUpdateParam(issuesRequest);
AddIssueResponse.Issue issue = zentaoClient.addIssue(param); AddIssueResponse.Issue issue = zentaoClient.addIssue(param);
issuesRequest.setPlatformStatus(issue.getStatus()); issuesRequest.setPlatformStatus(issue.getStatus());
IssuesWithBLOBs issues = null;
String id = issue.getId(); String id = issue.getId();
if (StringUtils.isNotBlank(id)) { if (StringUtils.isNotBlank(id)) {
issuesRequest.setPlatformId(id); issuesRequest.setPlatformId(id);
@ -170,12 +172,13 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
.andPlatformEqualTo(IssuesManagePlatform.Zentao.toString()); .andPlatformEqualTo(IssuesManagePlatform.Zentao.toString());
if (issuesMapper.selectByExample(issuesExample).size() <= 0) { if (issuesMapper.selectByExample(issuesExample).size() <= 0) {
// 插入缺陷表 // 插入缺陷表
insertIssues(issuesRequest); issues = insertIssues(issuesRequest);
} }
// 用例与第三方缺陷平台中的缺陷关联 // 用例与第三方缺陷平台中的缺陷关联
handleTestCaseIssues(issuesRequest); handleTestCaseIssues(issuesRequest);
} }
return issues;
} }
@Override @Override

View File

@ -88,15 +88,17 @@ public class IssuesService {
} }
public void addIssues(IssuesUpdateRequest issuesRequest) { public IssuesWithBLOBs addIssues(IssuesUpdateRequest issuesRequest) {
List<AbstractIssuePlatform> platformList = getAddPlatforms(issuesRequest); List<AbstractIssuePlatform> platformList = getAddPlatforms(issuesRequest);
platformList.forEach(platform -> { IssuesWithBLOBs issues = null;
platform.addIssue(issuesRequest); for (AbstractIssuePlatform platform : platformList) {
}); issues = platform.addIssue(issuesRequest);
}
issuesRequest.getTestCaseIds().forEach(l -> { issuesRequest.getTestCaseIds().forEach(l -> {
testCaseIssueService.updateIssuesCount(l); testCaseIssueService.updateIssuesCount(l);
}); });
saveFollows(issuesRequest.getId(), issuesRequest.getFollows()); saveFollows(issuesRequest.getId(), issuesRequest.getFollows());
return issues;
} }

View File

@ -15,6 +15,7 @@ import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.api.service.ApiTestCaseService; import io.metersphere.api.service.ApiTestCaseService;
import io.metersphere.base.domain.*; import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*; import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtIssuesMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper; import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.commons.constants.TestCaseConstants; import io.metersphere.commons.constants.TestCaseConstants;
import io.metersphere.commons.constants.TestCaseReviewStatus; import io.metersphere.commons.constants.TestCaseReviewStatus;
@ -85,6 +86,9 @@ public class TestCaseService {
@Resource @Resource
ExtTestCaseMapper extTestCaseMapper; ExtTestCaseMapper extTestCaseMapper;
@Resource
ExtIssuesMapper extIssuesMapper;
@Resource @Resource
UserService userService; UserService userService;
@ -1567,9 +1571,34 @@ public class TestCaseService {
return testCaseMapper.selectByExample(example); return testCaseMapper.selectByExample(example);
} }
public List<TestCaseWithBLOBs> listTestCaseForMinder(QueryTestCaseRequest request) { public List<TestCaseDTO> listTestCaseForMinder(QueryTestCaseRequest request) {
setDefaultOrder(request); setDefaultOrder(request);
return extTestCaseMapper.listForMinder(request); List<TestCaseDTO> cases = extTestCaseMapper.listForMinder(request);
List<String> caseIds = cases.stream().map(TestCaseDTO::getId).collect(Collectors.toList());
HashMap<String, List<IssuesDao>> issueMap = buildMinderIssueMap(caseIds);
for (TestCaseDTO item : cases) {
List<IssuesDao> issues = issueMap.get(item.getId());
if (issues != null) {
item.setIssueList(issues);
}
}
return cases;
}
public HashMap<String, List<IssuesDao>> buildMinderIssueMap(List<String> caseIds) {
HashMap<String, List<IssuesDao>> issueMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(caseIds)) {
List<IssuesDao> issues = extIssuesMapper.getIssueForMinder(caseIds);
for (IssuesDao item : issues) {
List<IssuesDao> list = issueMap.get(item.getCaseId());
if (list == null) {
list = new ArrayList<>();
}
list.add(item);
issueMap.put(item.getCaseId(), list);
}
}
return issueMap;
} }
public List<TestCaseDTO> getTestCaseByIds(List<String> testCaseIds) { public List<TestCaseDTO> getTestCaseByIds(List<String> testCaseIds) {

View File

@ -63,6 +63,8 @@ public class TestPlanTestCaseService {
private TestCaseTestMapper testCaseTestMapper; private TestCaseTestMapper testCaseTestMapper;
@Resource @Resource
private TestCaseCommentService testCaseCommentService; private TestCaseCommentService testCaseCommentService;
@Resource
private TestCaseService testCaseService;
public List<TestPlanTestCaseWithBLOBs> listAll() { public List<TestPlanTestCaseWithBLOBs> listAll() {
TestPlanTestCaseExample example = new TestPlanTestCaseExample(); TestPlanTestCaseExample example = new TestPlanTestCaseExample();
@ -307,7 +309,16 @@ public class TestPlanTestCaseService {
} }
}); });
request.setOrders(orders); request.setOrders(orders);
return extTestPlanTestCaseMapper.listForMinder(request); List<TestPlanCaseDTO> cases = extTestPlanTestCaseMapper.listForMinder(request);
List<String> caseIds = cases.stream().map(TestPlanCaseDTO::getCaseId).collect(Collectors.toList());
HashMap<String, List<IssuesDao>> issueMap = testCaseService.buildMinderIssueMap(caseIds);
for (TestPlanCaseDTO item : cases) {
List<IssuesDao> issues = issueMap.get(item.getCaseId());
if (issues != null) {
item.setIssueList(issues);
}
}
return cases;
} }
public void editTestCaseForMinder(List<TestPlanTestCaseWithBLOBs> testPlanTestCases) { public void editTestCaseForMinder(List<TestPlanTestCaseWithBLOBs> testPlanTestCases) {

@ -1 +1 @@
Subproject commit 33d1b2a4d29059882f026cb3f70653fca18381e4 Subproject commit 0a737ba93ccb914af26db8fed1ac6a927081816a

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.35", "vue-minder-editor-plus": "1.0.36",
"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

@ -72,13 +72,15 @@ import {ISSUE_STATUS_MAP} from "@/common/js/table-constants";
import MsTablePagination from "@/business/components/common/pagination/TablePagination"; import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import {getPageInfo} from "@/common/js/tableUtils"; import {getPageInfo} from "@/common/js/tableUtils";
import {getCurrentProjectID} from "@/common/js/utils"; import {getCurrentProjectID} from "@/common/js/utils";
import {getIssueTemplate} from "../../../../../network/custom-field-template";
export default { export default {
name: "IssueRelateList", name: "IssueRelateList",
components: {MsTablePagination, IssueDescriptionTableItem, MsTableColumn, MsTable, MsEditDialog}, components: {MsTablePagination, IssueDescriptionTableItem, MsTableColumn, MsTable, MsEditDialog},
data() { data() {
return { return {
page: getPageInfo(), page: getPageInfo(),
visible: false visible: false,
isThirdPart: false
} }
}, },
computed: { computed: {
@ -89,7 +91,17 @@ export default {
return getCurrentProjectID(); return getCurrentProjectID();
} }
}, },
props: ['caseId', 'isThirdPart'], props: ['caseId'],
created() {
getIssueTemplate()
.then((template) => {
if (template.platform === 'metersphere') {
this.isThirdPart = false;
} else {
this.isThirdPart = true;
}
});
},
methods: { methods: {
open() { open() {
this.getIssues(); this.getIssues();
@ -107,7 +119,7 @@ export default {
param.caseId = this.caseId; param.caseId = this.caseId;
testCaseIssueRelate(param, () => { testCaseIssueRelate(param, () => {
this.visible = false; this.visible = false;
this.$emit('refresh'); this.$emit('refresh', this.$refs.table.selectRows);
}); });
} }
} }

View File

@ -13,15 +13,6 @@
<el-col :span="7"> <el-col :span="7">
<el-form-item :label="$t('test_track.related_requirements')" :label-width="labelWidth" <el-form-item :label="$t('test_track.related_requirements')" :label-width="labelWidth"
prop="demandId"> prop="demandId">
<!-- <el-select filterable :disabled="readOnly" v-model="form.demandId" @visible-change="visibleChange"-->
<!-- :placeholder="$t('test_track.please_related_requirements')" class="ms-case-input">-->
<!-- <el-option-->
<!-- v-for="item in demandOptions"-->
<!-- :key="item.id"-->
<!-- :label="item.platform + ': '+item.name"-->
<!-- :value="item.id">-->
<!-- </el-option>-->
<!-- </el-select>-->
<el-cascader v-model="demandValue" :show-all-levels="false" :options="demandOptions" clearable/> <el-cascader v-model="demandValue" :show-all-levels="false" :options="demandOptions" clearable/>
</el-form-item> </el-form-item>

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<el-button class="add-btn" v-permission="['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']" :disabled="readOnly" type="primary" size="mini" @click="appIssue">{{ $t('test_track.issue.add_issue') }}</el-button> <el-button class="add-btn" v-permission="['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']" :disabled="readOnly" type="primary" size="mini" @click="addIssue">{{ $t('test_track.issue.add_issue') }}</el-button>
<el-button class="add-btn" v-permission="['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']" :disabled="readOnly" type="primary" size="mini" @click="relateIssue">{{ $t('test_track.case.relate_issue') }}</el-button> <el-button class="add-btn" v-permission="['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']" :disabled="readOnly" type="primary" size="mini" @click="relateIssue">{{ $t('test_track.case.relate_issue') }}</el-button>
<el-tooltip class="item" v-permission="['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']" effect="dark" <el-tooltip class="item" v-permission="['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL']" effect="dark"
:content="$t('test_track.issue.platform_tip')" :content="$t('test_track.issue.platform_tip')"
@ -86,7 +86,7 @@
</ms-table> </ms-table>
<test-plan-issue-edit :plan-id="planId" :case-id="caseId" @refresh="getIssues" ref="issueEdit"/> <test-plan-issue-edit :plan-id="planId" :case-id="caseId" @refresh="getIssues" ref="issueEdit"/>
<IssueRelateList :is-third-part="isThirdPart" :case-id="caseId" @refresh="getIssues" ref="issueRelate"/> <IssueRelateList :case-id="caseId" @refresh="getIssues" ref="issueRelate"/>
</div> </div>
</template> </template>
@ -120,7 +120,8 @@ export default {
exec: this.deleteIssue exec: this.deleteIssue
} }
], ],
status: [] status: [],
issueRelateVisible: false
} }
}, },
props: ['caseId', 'readOnly','planId'], props: ['caseId', 'readOnly','planId'],
@ -175,7 +176,7 @@ export default {
this.page.result = result; this.page.result = result;
} }
}, },
appIssue() { addIssue() {
if (!this.caseId) { if (!this.caseId) {
this.$warning(this.$t('api_test.automation.save_case_info')); this.$warning(this.$t('api_test.automation.save_case_info'));
return; return;

View File

@ -7,7 +7,7 @@
append-to-body append-to-body
ref="msEditDialog"> ref="msEditDialog">
<template v-slot:default="scope"> <template v-slot:default="scope">
<issue-edit-detail :plan-id="planId" :case-id="caseId" :is-plan="true" @refresh="$emit('refresh')" @close="handleClose" ref="issueEditDetail"/> <issue-edit-detail :plan-id="planId" :case-id="caseId" :is-plan="true" @refresh="refresh" @close="handleClose" ref="issueEditDetail"/>
</template> </template>
</ms-edit-dialog> </ms-edit-dialog>
</template> </template>
@ -44,6 +44,9 @@ export default {
}, },
confirm() { confirm() {
this.$refs.issueEditDetail.save(); this.$refs.issueEditDetail.save();
},
refresh(data) {
this.$emit('refresh', data);
} }
} }
}; };

View File

@ -1,20 +1,25 @@
<template> <template>
<ms-module-minder <div>
v-loading="result.loading" <ms-module-minder
:tree-nodes="treeNodes" v-loading="result.loading"
:tags="tags" :tree-nodes="treeNodes"
minder-key="testCase" :tags="tags"
:select-node="selectNode" minder-key="testCase"
:distinct-tags="tags" :select-node="selectNode"
:module-disable="false" :distinct-tags="tags"
:show-module-tag="true" :module-disable="false"
:tag-edit-check="tagEditCheck()" :show-module-tag="true"
@afterMount="handleAfterMount" :tag-edit-check="tagEditCheck()"
:priority-disable-check="priorityDisableCheck()" @afterMount="handleAfterMount"
:disabled="disabled" :priority-disable-check="priorityDisableCheck()"
@save="save" :disabled="disabled"
ref="minder" @save="save"
/> ref="minder"
/>
<IssueRelateList :case-id="getCurCaseId()" @refresh="refreshRelateIssue" ref="issueRelate"/>
<test-plan-issue-edit :plan-id="null" :case-id="getCurCaseId()" @refresh="refreshIssue" ref="issueEdit"/>
</div>
</template> </template>
<script> <script>
@ -31,9 +36,12 @@ import {
} from "@/business/components/track/common/minder/minderUtils"; } from "@/business/components/track/common/minder/minderUtils";
import {getNodePath, getUUID, 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";
import {addIssueHotBox, getSelectedNodeData, handleIssueAdd, handleIssueBatch} from "./minderUtils";
import IssueRelateList from "@/business/components/track/case/components/IssueRelateList";
import TestPlanIssueEdit from "@/business/components/track/case/components/TestPlanIssueEdit";
export default { export default {
name: "TestCaseMinder", name: "TestCaseMinder",
components: {MsModuleMinder}, components: {TestPlanIssueEdit, IssueRelateList, MsModuleMinder},
data() { data() {
return{ return{
testCase: [], testCase: [],
@ -120,6 +128,8 @@ name: "TestCaseMinder",
this.setIsChange(true); this.setIsChange(true);
} }
}); });
addIssueHotBox(this);
}, },
getParam() { getParam() {
return { return {
@ -433,6 +443,15 @@ name: "TestCaseMinder",
}); });
this.needRefresh = false; this.needRefresh = false;
} }
},
getCurCaseId() {
return getSelectedNodeData().id;
},
refreshIssue(issue) {
handleIssueAdd(issue);
},
refreshRelateIssue(issues) {
handleIssueBatch(issues);
} }
} }
} }

View File

@ -1,30 +1,37 @@
<template> <template>
<ms-module-minder <div>
v-loading="result.loading" <ms-module-minder
:tree-nodes="treeNodes" v-loading="result.loading"
:data-map="dataMap" :tree-nodes="treeNodes"
:tags="tags" :data-map="dataMap"
:tag-enable="true" :tags="tags"
minder-key="testPlan" :tag-enable="true"
:select-node="selectNode" minder-key="testPlan"
:distinct-tags="[...tags, this.$t('test_track.plan.plan_status_prepare')]" :select-node="selectNode"
:ignore-num="true" :distinct-tags="[...tags, this.$t('test_track.plan.plan_status_prepare')]"
@afterMount="handleAfterMount" :ignore-num="true"
@save="save" @afterMount="handleAfterMount"
ref="minder" @save="save"
/> ref="minder"
/>
<IssueRelateList :case-id="getCurCaseId()" @refresh="refreshRelateIssue" ref="issueRelate"/>
<test-plan-issue-edit :plan-id="planId" :case-id="getCurCaseId()" @refresh="refreshIssue" ref="issueEdit"/>
</div>
</template> </template>
<script> <script>
import MsModuleMinder from "@/business/components/common/components/MsModuleMinder"; import MsModuleMinder from "@/business/components/common/components/MsModuleMinder";
import { import {
handleExpandToLevel, listenBeforeExecCommand, listenNodeSelected, loadSelectNodes, handleExpandToLevel, listenBeforeExecCommand, listenNodeSelected, loadSelectNodes,
tagBatch, tagBatch, getSelectedNodeData, handleIssueAdd, handleIssueBatch
} from "@/business/components/track/common/minder/minderUtils"; } from "@/business/components/track/common/minder/minderUtils";
import {getPlanCasesForMinder} from "@/network/testCase"; import {getPlanCasesForMinder} from "@/network/testCase";
import IssueRelateList from "@/business/components/track/case/components/IssueRelateList";
import TestPlanIssueEdit from "@/business/components/track/case/components/TestPlanIssueEdit";
import {addIssueHotBox} from "./minderUtils";
export default { export default {
name: "TestPlanMinder", name: "TestPlanMinder",
components: {MsModuleMinder}, components: {MsModuleMinder, TestPlanIssueEdit, IssueRelateList},
data() { data() {
return{ return{
dataMap: new Map(), dataMap: new Map(),
@ -81,6 +88,8 @@ name: "TestPlanMinder",
}); });
tagBatch([...this.tags, this.$t('test_track.plan.plan_status_prepare')]); tagBatch([...this.tags, this.$t('test_track.plan.plan_status_prepare')]);
addIssueHotBox(this);
}, },
getParam() { getParam() {
return { return {
@ -144,6 +153,15 @@ name: "TestPlanMinder",
} }
} }
saveCases.push(testCase); saveCases.push(testCase);
},
getCurCaseId() {
return getSelectedNodeData().caseId;
},
refreshIssue(issue) {
handleIssueAdd(issue);
},
refreshRelateIssue(issues) {
handleIssueBatch(issues);
} }
} }
} }

View File

@ -1,5 +1,6 @@
import i18n from "@/i18n/i18n"; import i18n from "@/i18n/i18n";
import {getCurrentProjectID} from "../../../../../common/js/utils"; import {getCurrentProjectID} from "../../../../../common/js/utils";
import {warning} from "../../../../../common/js/message";
export function listenNodeSelected(callback) { export function listenNodeSelected(callback) {
let minder = window.minder; let minder = window.minder;
@ -107,6 +108,23 @@ export function handleTestCaseAdd(pid, data) {
}); });
} }
export function handleIssueAdd(data) {
let pNode = getSelectedNode();
appendChildNode(pNode, getNodeData('缺陷ID' + data.num, null, true));
expandNode(pNode);
pNode.render();
}
export function handleIssueBatch(issues) {
let pNode = getSelectedNode();
issues.forEach(item => {
appendChildNode(pNode, getNodeData('缺陷ID' + item.num, null, true));
});
expandNode(pNode);
pNode.render();
}
export function handTestCaeEdit(data) { export function handTestCaeEdit(data) {
window.minder.getRoot().traverse(function(node) { window.minder.getRoot().traverse(function(node) {
if (node.data.id === data.id) { if (node.data.id === data.id) {
@ -181,7 +199,8 @@ export function appendCase(parent, item, isDisable, setParamCallback) {
type: 'case', type: 'case',
method: item.method, method: item.method,
maintainer: item.maintainer, maintainer: item.maintainer,
stepModel: item.stepModel stepModel: item.stepModel,
caseId: item.caseId
} }
if (setParamCallback) { if (setParamCallback) {
setParamCallback(caseData, item); setParamCallback(caseData, item);
@ -219,6 +238,12 @@ export function appendCase(parent, item, isDisable, setParamCallback) {
}); });
} }
} }
if (item.issueList && item.issueList.length > 0) {
item.issueList.forEach(issue => {
appendChildNode(caseNode, getNodeData('缺陷ID' + issue.num, null, true));
});
}
} }
function getNodeData(text, resource, isDisable) { function getNodeData(text, resource, isDisable) {
@ -359,6 +384,11 @@ export function isModuleNodeData(data) {
return data.type === 'node' || (resource && resource.indexOf(i18n.t('test_track.module.module')) > -1); return data.type === 'node' || (resource && resource.indexOf(i18n.t('test_track.module.module')) > -1);
} }
export function isCaseNodeData(data) {
let resource = data ? data.resource : null;
return data.type === 'case' || (resource && resource.indexOf(i18n.t('api_test.definition.request.case')) > -1);
}
export function isModuleNode(node) { export function isModuleNode(node) {
return isModuleNodeData(node.data); return isModuleNodeData(node.data);
} }
@ -427,3 +457,52 @@ export function getChildNodeId(rootNode, nodeIds) {
} }
} }
} }
export function getSelectedNode() {
return window.minder ? window.minder.getSelectedNode() : null;
}
export function getSelectedNodeData() {
let node = getSelectedNode();
return node ? node.data : {};
}
export function addIssueHotBox(vueObj) {
let hotbox = window.minder.hotbox;
let main = hotbox.state('main');
main.button({
position: 'ring',
label: '关联缺陷',
key: 'N',
action: function () {
if (getSelectedNodeData().id.length < 15) {
warning("请先保存用例");
return;
}
vueObj.$refs.issueRelate.open();
},
enable: function () {
return isCaseNodeData(getSelectedNodeData());
},
beforeShow: function () {
}
});
main.button({
position: 'ring',
label: '添加缺陷',
key: 'M',
action: function () {
if (getSelectedNodeData().id.length < 15) {
warning("请先保存用例");
return;
}
vueObj.$refs.issueEdit.open();
},
enable: function () {
return isCaseNodeData(getSelectedNodeData());
},
beforeShow: function () {
}
});
}

View File

@ -11,7 +11,7 @@
> >
<template v-slot:default="scope"> <template v-slot:default="scope">
<template-component-edit-header :show-edit="false" :template="{}" prop="title" @cancel="handleClose" @save="save"/> <template-component-edit-header :show-edit="false" :template="{}" prop="title" @cancel="handleClose" @save="save"/>
<issue-edit-detail @refresh="$emit('refresh')" @close="handleClose" ref="issueEditDetail"/> <issue-edit-detail @refresh="refresh" @close="handleClose" ref="issueEditDetail"/>
</template> </template>
</el-drawer> </el-drawer>
</template> </template>
@ -40,6 +40,9 @@ export default {
}, },
save() { save() {
this.$refs.issueEditDetail.save(); this.$refs.issueEditDetail.save();
},
refresh(data) {
this.$emit('refresh', data);
} }
} }
}; };

View File

@ -286,10 +286,10 @@ export default {
_save() { _save() {
let param = this.buildPram(); let param = this.buildPram();
this.parseOldFields(param); this.parseOldFields(param);
this.result = this.$post(this.url, param, () => { this.result = this.$post(this.url, param, (response) => {
this.$emit('close'); this.$emit('close');
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
this.$emit('refresh'); this.$emit('refresh', response.data);
}); });
}, },
parseOldFields(param) { parseOldFields(param) {