feat(测试跟踪): 功能用例缺陷与测试计划缺陷分离

This commit is contained in:
chenjianxing 2022-02-16 10:01:23 +08:00 committed by jianxing
parent 063071a305
commit 4cb76a97c2
31 changed files with 551 additions and 265 deletions

View File

@ -7,9 +7,13 @@ import lombok.Data;
public class TestCaseIssues implements Serializable {
private String id;
private String testCaseId;
private String resourceId;
private String issuesId;
private String refId;
private String refType;
private static final long serialVersionUID = 1L;
}

View File

@ -174,73 +174,73 @@ public class TestCaseIssuesExample {
return (Criteria) this;
}
public Criteria andTestCaseIdIsNull() {
addCriterion("test_case_id is null");
public Criteria andResourceIdIsNull() {
addCriterion("resource_id is null");
return (Criteria) this;
}
public Criteria andTestCaseIdIsNotNull() {
addCriterion("test_case_id is not null");
public Criteria andResourceIdIsNotNull() {
addCriterion("resource_id is not null");
return (Criteria) this;
}
public Criteria andTestCaseIdEqualTo(String value) {
addCriterion("test_case_id =", value, "testCaseId");
public Criteria andResourceIdEqualTo(String value) {
addCriterion("resource_id =", value, "resourceId");
return (Criteria) this;
}
public Criteria andTestCaseIdNotEqualTo(String value) {
addCriterion("test_case_id <>", value, "testCaseId");
public Criteria andResourceIdNotEqualTo(String value) {
addCriterion("resource_id <>", value, "resourceId");
return (Criteria) this;
}
public Criteria andTestCaseIdGreaterThan(String value) {
addCriterion("test_case_id >", value, "testCaseId");
public Criteria andResourceIdGreaterThan(String value) {
addCriterion("resource_id >", value, "resourceId");
return (Criteria) this;
}
public Criteria andTestCaseIdGreaterThanOrEqualTo(String value) {
addCriterion("test_case_id >=", value, "testCaseId");
public Criteria andResourceIdGreaterThanOrEqualTo(String value) {
addCriterion("resource_id >=", value, "resourceId");
return (Criteria) this;
}
public Criteria andTestCaseIdLessThan(String value) {
addCriterion("test_case_id <", value, "testCaseId");
public Criteria andResourceIdLessThan(String value) {
addCriterion("resource_id <", value, "resourceId");
return (Criteria) this;
}
public Criteria andTestCaseIdLessThanOrEqualTo(String value) {
addCriterion("test_case_id <=", value, "testCaseId");
public Criteria andResourceIdLessThanOrEqualTo(String value) {
addCriterion("resource_id <=", value, "resourceId");
return (Criteria) this;
}
public Criteria andTestCaseIdLike(String value) {
addCriterion("test_case_id like", value, "testCaseId");
public Criteria andResourceIdLike(String value) {
addCriterion("resource_id like", value, "resourceId");
return (Criteria) this;
}
public Criteria andTestCaseIdNotLike(String value) {
addCriterion("test_case_id not like", value, "testCaseId");
public Criteria andResourceIdNotLike(String value) {
addCriterion("resource_id not like", value, "resourceId");
return (Criteria) this;
}
public Criteria andTestCaseIdIn(List<String> values) {
addCriterion("test_case_id in", values, "testCaseId");
public Criteria andResourceIdIn(List<String> values) {
addCriterion("resource_id in", values, "resourceId");
return (Criteria) this;
}
public Criteria andTestCaseIdNotIn(List<String> values) {
addCriterion("test_case_id not in", values, "testCaseId");
public Criteria andResourceIdNotIn(List<String> values) {
addCriterion("resource_id not in", values, "resourceId");
return (Criteria) this;
}
public Criteria andTestCaseIdBetween(String value1, String value2) {
addCriterion("test_case_id between", value1, value2, "testCaseId");
public Criteria andResourceIdBetween(String value1, String value2) {
addCriterion("resource_id between", value1, value2, "resourceId");
return (Criteria) this;
}
public Criteria andTestCaseIdNotBetween(String value1, String value2) {
addCriterion("test_case_id not between", value1, value2, "testCaseId");
public Criteria andResourceIdNotBetween(String value1, String value2) {
addCriterion("resource_id not between", value1, value2, "resourceId");
return (Criteria) this;
}
@ -313,6 +313,146 @@ public class TestCaseIssuesExample {
addCriterion("issues_id not between", value1, value2, "issuesId");
return (Criteria) this;
}
public Criteria andRefIdIsNull() {
addCriterion("ref_id is null");
return (Criteria) this;
}
public Criteria andRefIdIsNotNull() {
addCriterion("ref_id is not null");
return (Criteria) this;
}
public Criteria andRefIdEqualTo(String value) {
addCriterion("ref_id =", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotEqualTo(String value) {
addCriterion("ref_id <>", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdGreaterThan(String value) {
addCriterion("ref_id >", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdGreaterThanOrEqualTo(String value) {
addCriterion("ref_id >=", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLessThan(String value) {
addCriterion("ref_id <", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLessThanOrEqualTo(String value) {
addCriterion("ref_id <=", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdLike(String value) {
addCriterion("ref_id like", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotLike(String value) {
addCriterion("ref_id not like", value, "refId");
return (Criteria) this;
}
public Criteria andRefIdIn(List<String> values) {
addCriterion("ref_id in", values, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotIn(List<String> values) {
addCriterion("ref_id not in", values, "refId");
return (Criteria) this;
}
public Criteria andRefIdBetween(String value1, String value2) {
addCriterion("ref_id between", value1, value2, "refId");
return (Criteria) this;
}
public Criteria andRefIdNotBetween(String value1, String value2) {
addCriterion("ref_id not between", value1, value2, "refId");
return (Criteria) this;
}
public Criteria andRefTypeIsNull() {
addCriterion("ref_type is null");
return (Criteria) this;
}
public Criteria andRefTypeIsNotNull() {
addCriterion("ref_type is not null");
return (Criteria) this;
}
public Criteria andRefTypeEqualTo(String value) {
addCriterion("ref_type =", value, "refType");
return (Criteria) this;
}
public Criteria andRefTypeNotEqualTo(String value) {
addCriterion("ref_type <>", value, "refType");
return (Criteria) this;
}
public Criteria andRefTypeGreaterThan(String value) {
addCriterion("ref_type >", value, "refType");
return (Criteria) this;
}
public Criteria andRefTypeGreaterThanOrEqualTo(String value) {
addCriterion("ref_type >=", value, "refType");
return (Criteria) this;
}
public Criteria andRefTypeLessThan(String value) {
addCriterion("ref_type <", value, "refType");
return (Criteria) this;
}
public Criteria andRefTypeLessThanOrEqualTo(String value) {
addCriterion("ref_type <=", value, "refType");
return (Criteria) this;
}
public Criteria andRefTypeLike(String value) {
addCriterion("ref_type like", value, "refType");
return (Criteria) this;
}
public Criteria andRefTypeNotLike(String value) {
addCriterion("ref_type not like", value, "refType");
return (Criteria) this;
}
public Criteria andRefTypeIn(List<String> values) {
addCriterion("ref_type in", values, "refType");
return (Criteria) this;
}
public Criteria andRefTypeNotIn(List<String> values) {
addCriterion("ref_type not in", values, "refType");
return (Criteria) this;
}
public Criteria andRefTypeBetween(String value1, String value2) {
addCriterion("ref_type between", value1, value2, "refType");
return (Criteria) this;
}
public Criteria andRefTypeNotBetween(String value1, String value2) {
addCriterion("ref_type not between", value1, value2, "refType");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -3,8 +3,10 @@
<mapper namespace="io.metersphere.base.mapper.TestCaseIssuesMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.TestCaseIssues">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="test_case_id" jdbcType="VARCHAR" property="testCaseId" />
<result column="resource_id" jdbcType="VARCHAR" property="resourceId" />
<result column="issues_id" jdbcType="VARCHAR" property="issuesId" />
<result column="ref_id" jdbcType="VARCHAR" property="refId" />
<result column="ref_type" jdbcType="VARCHAR" property="refType" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -65,7 +67,7 @@
</where>
</sql>
<sql id="Base_Column_List">
id, test_case_id, issues_id
id, resource_id, issues_id, ref_id, ref_type
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestCaseIssuesExample" resultMap="BaseResultMap">
select
@ -98,10 +100,10 @@
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestCaseIssues">
insert into test_case_issues (id, test_case_id, issues_id
)
values (#{id,jdbcType=VARCHAR}, #{testCaseId,jdbcType=VARCHAR}, #{issuesId,jdbcType=VARCHAR}
)
insert into test_case_issues (id, resource_id, issues_id,
ref_id, ref_type)
values (#{id,jdbcType=VARCHAR}, #{resourceId,jdbcType=VARCHAR}, #{issuesId,jdbcType=VARCHAR},
#{refId,jdbcType=VARCHAR}, #{refType,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestCaseIssues">
insert into test_case_issues
@ -109,23 +111,35 @@
<if test="id != null">
id,
</if>
<if test="testCaseId != null">
test_case_id,
<if test="resourceId != null">
resource_id,
</if>
<if test="issuesId != null">
issues_id,
</if>
<if test="refId != null">
ref_id,
</if>
<if test="refType != null">
ref_type,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="testCaseId != null">
#{testCaseId,jdbcType=VARCHAR},
<if test="resourceId != null">
#{resourceId,jdbcType=VARCHAR},
</if>
<if test="issuesId != null">
#{issuesId,jdbcType=VARCHAR},
</if>
<if test="refId != null">
#{refId,jdbcType=VARCHAR},
</if>
<if test="refType != null">
#{refType,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestCaseIssuesExample" resultType="java.lang.Long">
@ -140,12 +154,18 @@
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.testCaseId != null">
test_case_id = #{record.testCaseId,jdbcType=VARCHAR},
<if test="record.resourceId != null">
resource_id = #{record.resourceId,jdbcType=VARCHAR},
</if>
<if test="record.issuesId != null">
issues_id = #{record.issuesId,jdbcType=VARCHAR},
</if>
<if test="record.refId != null">
ref_id = #{record.refId,jdbcType=VARCHAR},
</if>
<if test="record.refType != null">
ref_type = #{record.refType,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -154,8 +174,10 @@
<update id="updateByExample" parameterType="map">
update test_case_issues
set id = #{record.id,jdbcType=VARCHAR},
test_case_id = #{record.testCaseId,jdbcType=VARCHAR},
issues_id = #{record.issuesId,jdbcType=VARCHAR}
resource_id = #{record.resourceId,jdbcType=VARCHAR},
issues_id = #{record.issuesId,jdbcType=VARCHAR},
ref_id = #{record.refId,jdbcType=VARCHAR},
ref_type = #{record.refType,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -163,19 +185,27 @@
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.TestCaseIssues">
update test_case_issues
<set>
<if test="testCaseId != null">
test_case_id = #{testCaseId,jdbcType=VARCHAR},
<if test="resourceId != null">
resource_id = #{resourceId,jdbcType=VARCHAR},
</if>
<if test="issuesId != null">
issues_id = #{issuesId,jdbcType=VARCHAR},
</if>
<if test="refId != null">
ref_id = #{refId,jdbcType=VARCHAR},
</if>
<if test="refType != null">
ref_type = #{refType,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestCaseIssues">
update test_case_issues
set test_case_id = #{testCaseId,jdbcType=VARCHAR},
issues_id = #{issuesId,jdbcType=VARCHAR}
set resource_id = #{resourceId,jdbcType=VARCHAR},
issues_id = #{issuesId,jdbcType=VARCHAR},
ref_id = #{refId,jdbcType=VARCHAR},
ref_type = #{refType,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

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

View File

@ -7,25 +7,33 @@
from issues
inner join test_case_issues
on test_case_issues.issues_id = issues.id
<if test="request.projectId != null||request.workspaceId != null">
left join
project on issues.project_id = project.id
</if>
<include refid="queryWhereCondition"/>
and (issues.platform_status != 'delete' or issues.platform_status is NULL)
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</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
select issues.id, issues.title , issues.num , test_case_issues.resource_id as caseId
from issues
inner join test_case_issues
on test_case_issues.issues_id = issues.id
where test_case_id in
where (issues.platform_status != 'delete' or issues.platform_status is NULL)
<if test="refType == 'FUNCTIONAL'">
and test_case_issues.resource_id in
<foreach collection="caseIds" open="(" close=")" item="item" separator=",">
#{item}
</foreach>
and (issues.platform_status != 'delete' or issues.platform_status is NULL)
or test_case_issues.ref_id in
<foreach collection="caseIds" open="(" close=")" item="item" separator=",">
#{item}
</foreach>
</if>
<if test="refType == 'PLAN_FUNCTIONAL'">
and test_case_issues.resource_id in
<foreach collection="caseIds" open="(" close=")" item="item" separator=",">
#{item}
</foreach>
</if>
order by num asc
</select>
@ -54,13 +62,13 @@
</select>
<select id="getRelateIssues" resultType="io.metersphere.base.domain.IssuesDao">
select issues.id, issues.num, issues.title, issues.project_id, issues.create_time, issues.update_time,
issues.description, issues.status, issues.platform, issues.custom_fields,test_case_issues.test_case_id,issues.platform_status,
issues.description, issues.status, issues.platform, issues.custom_fields,test_case_issues.resource_id,issues.platform_status,
issues.lastmodify
from issues
left join
test_case_issues on issues.id = test_case_issues.issues_id
<include refid="queryWhereCondition"/>
and (test_case_issues.test_case_id is null or test_case_issues.test_case_id != #{request.caseId})
and (test_case_issues.resource_id is null or test_case_issues.resource_id != #{request.caseResourceId})
and (issues.platform_status != 'delete' or issues.platform_status is NULL)
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
group by issues.id
@ -107,8 +115,13 @@
and issues.resource_id = #{request.resourceId}
</if>
<if test="request.testCaseId != null and request.testCaseId != ''">
and test_case_issues.test_case_id = #{request.testCaseId}
<if test="request.caseResourceId != null and request.caseResourceId != ''">
<if test="request.refType == 'FUNCTIONAL'">
and (test_case_issues.resource_id = #{request.caseResourceId} or test_case_issues.ref_id = #{request.caseResourceId})
</if>
<if test="request.refType == 'PLAN_FUNCTIONAL'">
and test_case_issues.resource_id = #{request.caseResourceId}
</if>
</if>
<if test="request.platform != null and request.platform != ''">
@ -118,13 +131,6 @@
and issues.id = #{request.id}
</if>
<!-- <if test="request.ids != null and request.ids.size() > 0">-->
<!-- and issues.id in-->
<!-- <foreach collection="request.ids" item="id" separator="," open="(" close=")">-->
<!-- #{id}-->
<!-- </foreach>-->
<!-- </if>-->
<if test="request.filters != null and request.filters.size() > 0">
<foreach collection="request.filters.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">

View File

@ -249,8 +249,8 @@
<select id="getProjectPlanBugSize" resultType="java.lang.Integer">
select count(distinct (tci.issues_id))
from test_plan_test_case tptc
join test_case_issues tci on tptc.case_id = tci.test_case_id
right join test_case on test_case.id = tci.test_case_id
join test_case_issues tci on tptc.case_id = tci.resource_id
right join test_case on test_case.id = tci.resource_id
join issues on tci.issues_id = issues.id
join test_plan on tptc.plan_id = test_plan.id
where test_plan.project_id = #{projectId}

View File

@ -724,9 +724,9 @@
<select id="getTestPlanBug" resultType="int">
select count(distinct (tci.issues_id))
from test_plan_test_case tptc
join test_case_issues tci on tptc.case_id = tci.test_case_id
join test_case_issues tci on tptc.case_id = tci.resource_id
right join test_case
on test_case.id = tci.test_case_id
on test_case.id = tci.resource_id
join issues
on tci.issues_id = issues.id
where tptc.plan_id = #{planId}

View File

@ -0,0 +1,5 @@
package io.metersphere.commons.constants;
public enum IssueRefType {
FUNCTIONAL, PLAN_FUNCTIONAL
}

View File

@ -67,10 +67,10 @@ public class IssuesController {
issuesService.updateIssues(issuesRequest);
}
@GetMapping("/get/case/{id}")
@GetMapping("/get/case/{refType}/{id}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_ISSUE_READ)
public List<IssuesDao> getIssues(@PathVariable String id) {
return issuesService.getIssues(id);
public List<IssuesDao> getIssues(@PathVariable String refType, @PathVariable String id) {
return issuesService.getIssues(id, refType);
}
@GetMapping("/get/{id}")
@ -100,13 +100,6 @@ public class IssuesController {
issuesService.closeLocalIssue(id);
}
@PostMapping("/delete")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_ISSUE_READ_DELETE)
@MsAuditLog(module = OperLogModule.TRACK_BUG, type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#request.id)", msClass = IssuesService.class)
public void deleteIssue(@RequestBody IssuesRequest request) {
issuesService.deleteIssue(request);
}
@PostMapping("/delete/relate")
public void deleteRelate(@RequestBody IssuesRequest request) {
issuesService.deleteIssueRelate(request);

View File

@ -1,10 +1,8 @@
package io.metersphere.track.domain;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.TestCaseNode;
import io.metersphere.base.domain.TestCaseNodeExample;
import io.metersphere.base.mapper.TestCaseNodeMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseNodeMapper;
import io.metersphere.commons.constants.IssueRefType;
import io.metersphere.commons.constants.TestPlanTestCaseStatus;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.MathUtils;
@ -124,7 +122,7 @@ public class ReportResultComponent extends ReportComponent {
if (StringUtils.equals(testCase.getStatus(), TestPlanTestCaseStatus.Blocking.name())) {
moduleResult.setBlockingCount(moduleResult.getBlockingCount() + 1);
}
moduleResult.setIssuesCount(moduleResult.getIssuesCount() + issuesService.getIssues(testCase.getCaseId()).size());
moduleResult.setIssuesCount(moduleResult.getIssuesCount() + issuesService.getIssues(testCase.getId(), IssueRefType.PLAN_FUNCTIONAL.name()).size());
moduleResultMap.put(rootNodeId, moduleResult);
return;
}

View File

@ -8,6 +8,7 @@ import io.metersphere.base.mapper.ProjectMapper;
import io.metersphere.base.mapper.TestCaseIssuesMapper;
import io.metersphere.base.mapper.ext.ExtIssuesMapper;
import io.metersphere.commons.constants.CustomFieldType;
import io.metersphere.commons.constants.IssueRefType;
import io.metersphere.commons.constants.IssuesStatus;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
@ -170,52 +171,35 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
return issueConfig;
}
protected boolean isIntegratedPlatform(String workspaceId, String platform) {
IntegrationRequest request = new IntegrationRequest();
request.setPlatform(platform);
request.setWorkspaceId(workspaceId);
ServiceIntegration integration = integrationService.get(request);
return StringUtils.isNotBlank(integration.getId());
}
protected void insertTestCaseIssues(String issuesId, String caseId) {
if (StringUtils.isNotBlank(caseId)) {
TestCaseIssues testCaseIssues = new TestCaseIssues();
testCaseIssues.setId(UUID.randomUUID().toString());
testCaseIssues.setIssuesId(issuesId);
testCaseIssues.setTestCaseId(caseId);
testCaseIssuesMapper.insert(testCaseIssues);
testCaseIssueService.updateIssuesCount(caseId);
}
}
protected void handleIssueUpdate(IssuesUpdateRequest request) {
request.setUpdateTime(System.currentTimeMillis());
issuesMapper.updateByPrimaryKeySelective(request);
if (!request.isWithoutTestCaseIssue()) {
handleTestCaseIssues(request);
}
}
protected void handleTestCaseIssues(IssuesUpdateRequest issuesRequest) {
String issuesId = issuesRequest.getId();
if (StringUtils.isNotBlank(issuesRequest.getTestCaseId())) {
insertTestCaseIssues(issuesId, issuesRequest.getTestCaseId());
} else {
List<String> testCaseIds = issuesRequest.getTestCaseIds();
List<String> deleteCaseIds = issuesRequest.getDeleteResourceIds();
if (!CollectionUtils.isEmpty(deleteCaseIds)) {
TestCaseIssuesExample example = new TestCaseIssuesExample();
example.createCriteria().andIssuesIdEqualTo(issuesId);
List<TestCaseIssues> testCaseIssues = testCaseIssuesMapper.selectByExample(example);
List<String> deleteCaseIds = testCaseIssues.stream().map(TestCaseIssues::getTestCaseId).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(testCaseIds)) {
deleteCaseIds.removeAll(testCaseIds);
}
example.createCriteria().andResourceIdIn(deleteCaseIds);
// 测试计划的用例 deleteCaseIds 是空的 不会进到这里
example.or(example.createCriteria().andRefIdIn(deleteCaseIds));
testCaseIssuesMapper.deleteByExample(example);
deleteCaseIds.forEach(testCaseIssueService::updateIssuesCount);
if (!CollectionUtils.isEmpty(testCaseIds)) {
testCaseIds.forEach(caseId -> {
insertTestCaseIssues(issuesId, caseId);
}
List<String> addCaseIds = issuesRequest.getAddResourceIds();
TestCaseIssueService testCaseIssueService = CommonBeanFactory.getBean(TestCaseIssueService.class);
if (!CollectionUtils.isEmpty(addCaseIds)) {
if (issuesRequest.getIsPlanEdit()) {
addCaseIds.forEach(caseId -> {
testCaseIssueService.add(issuesId, caseId, issuesRequest.getRefId(), IssueRefType.PLAN_FUNCTIONAL.name());
testCaseIssueService.updateIssuesCount(caseId);
});
} else {
addCaseIds.forEach(caseId -> testCaseIssueService.add(issuesId, caseId, null, IssueRefType.FUNCTIONAL.name()));
}
}
}
@ -380,11 +364,8 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
@Override
public void deleteIssue(String id) {
issuesMapper.deleteByPrimaryKey(id);
TestCaseIssuesExample example = new TestCaseIssuesExample();
example.createCriteria()
.andIssuesIdEqualTo(id);
testCaseIssuesMapper.deleteByExample(example);
IssuesService issuesService = CommonBeanFactory.getBean(IssuesService.class);
issuesService.deleteIssue(id);
}
protected void addCustomFields(IssuesUpdateRequest issuesRequest, MultiValueMap<String, Object> paramMap) {

View File

@ -34,4 +34,9 @@ public class IssuesRelevanceRequest {
private Boolean checked;
private String description;
private String caseResourceId;
private List<String> caseResourceIds;
private Boolean isPlanEdit = false;
private String refId;
}

View File

@ -15,6 +15,12 @@ public class IssuesRequest extends BaseQueryRequest {
private String testCaseId;
private List<String> tapdUsers;
private String userId;
/**
* 关联类型
* 如果类型是 FUNCTIONAL 表示是功能用例查询相关缺陷此时需要把该功能用例对应的测试计划中的用例关联的缺陷一并查出
* 如果是 PLAN_FUNCTIONAL 则只查询该测试计划用例所关联的缺陷
*/
private String refType;
/**
* zentao bug 处理人
*/
@ -30,6 +36,10 @@ public class IssuesRequest extends BaseQueryRequest {
private String id;
private String caseId;
private String resourceId;
/**
* 查询用例下的缺陷的用例id或者测试计划的用例id
*/
private String caseResourceId;
private String platform;
private String customFields;
private List<String> testCaseIds;
@ -37,4 +47,5 @@ public class IssuesRequest extends BaseQueryRequest {
private String requestType;
private String status;
private String defaultCustomFields;
private Boolean isPlanEdit = false;
}

View File

@ -10,7 +10,6 @@ import java.util.List;
@Setter
public class IssuesUpdateRequest extends IssuesWithBLOBs {
private String content;
private String testCaseId;
private String workspaceId;
private List<String> tapdUsers;
@ -23,11 +22,12 @@ public class IssuesUpdateRequest extends IssuesWithBLOBs {
* zentao bug 影响版本
*/
private List<String> zentaoBuilds;
private List<String> testCaseIds;
private boolean thirdPartPlatform;
private List<String> follows;
private boolean withoutTestCaseIssue; // 不更新用例和缺陷的关联关系
private List<String> addResourceIds;
private List<String> deleteResourceIds;
private Boolean isPlanEdit = false;
private String refId;
}

View File

@ -8,6 +8,7 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtIssuesMapper;
import io.metersphere.commons.constants.IssueRefType;
import io.metersphere.commons.constants.IssuesManagePlatform;
import io.metersphere.commons.constants.IssuesStatus;
import io.metersphere.commons.exception.MSException;
@ -94,9 +95,11 @@ public class IssuesService {
for (AbstractIssuePlatform platform : platformList) {
issues = platform.addIssue(issuesRequest);
}
issuesRequest.getTestCaseIds().forEach(l -> {
if (issuesRequest.getIsPlanEdit()) {
issuesRequest.getAddResourceIds().forEach(l -> {
testCaseIssueService.updateIssuesCount(l);
});
}
saveFollows(issuesRequest.getId(), issuesRequest.getFollows());
return issues;
}
@ -128,13 +131,13 @@ public class IssuesService {
public List<AbstractIssuePlatform> getAddPlatforms(IssuesUpdateRequest updateRequest) {
List<String> platforms = new ArrayList<>();
if (StringUtils.isNotBlank(updateRequest.getTestCaseId())) {
// 测试计划关联
platforms.add(getPlatformsByCaseId(updateRequest.getTestCaseId()));
} else {
// if (StringUtils.isNotBlank(updateRequest.getTestCaseId())) {
// // 测试计划关联
// platforms.add(getPlatformsByCaseId(updateRequest.getTestCaseId()));
// } else {
// 缺陷管理关联
platforms.add(getPlatform(updateRequest.getProjectId()));
}
// }
if (CollectionUtils.isEmpty(platforms)) {
platforms.add(IssuesManagePlatform.Local.toString());
@ -159,37 +162,18 @@ public class IssuesService {
return IssueFactory.createPlatforms(platforms, issuesRequest);
}
public List<IssuesDao> getIssues(String caseId) {
public List<IssuesDao> getIssues(String caseResourceId, String refType) {
IssuesRequest issueRequest = new IssuesRequest();
issueRequest.setTestCaseId(caseId);
issueRequest.setCaseResourceId(caseResourceId);
ServiceUtils.getDefaultOrder(issueRequest.getOrders());
Project project = getProjectByCaseId(caseId);
// project 不存在
if (project == null) {
return null;
}
String workspaceId = project.getWorkspaceId();
TestCase testCase = testCaseMapper.selectByPrimaryKey(caseId);
String userId = testCase.getMaintainer();
issueRequest.setWorkspaceId(workspaceId);
issueRequest.setUserId(userId);
return getIssuesByProjectIdOrCaseId(issueRequest);
issueRequest.setRefType(refType);
return extIssuesMapper.getIssuesByCaseId(issueRequest);
}
public IssuesWithBLOBs getIssue(String id) {
return issuesMapper.selectByPrimaryKey(id);
}
public List<IssuesDao> getIssuesByProjectIdOrCaseId(IssuesRequest issueRequest) {
List<IssuesDao> issues;
if (StringUtils.isNotBlank(issueRequest.getProjectId())) {
issues = extIssuesMapper.getIssues(issueRequest);
} else {
issues = extIssuesMapper.getIssuesByCaseId(issueRequest);
}
return issues;
}
public String getPlatformsByCaseId(String caseId) {
TestCaseWithBLOBs testCase = testCaseService.getTestCase(caseId);
Project project = projectService.getProjectById(testCase.getProjectId());
@ -288,18 +272,28 @@ public class IssuesService {
return platform.getPlatformUser();
}
public void deleteIssue(IssuesRequest request) {
issuesMapper.deleteByPrimaryKey(request.getId());
deleteIssueRelate(request);
public void deleteIssue(String id) {
issuesMapper.deleteByPrimaryKey(id);
TestCaseIssuesExample example = new TestCaseIssuesExample();
example.createCriteria().andIssuesIdEqualTo(id);
List<TestCaseIssues> testCaseIssues = testCaseIssuesMapper.selectByExample(example);
testCaseIssues.forEach(i -> {
if (i.getRefType().equals(IssueRefType.PLAN_FUNCTIONAL)) {
testCaseIssueService.updateIssuesCount(i.getResourceId());
}
});
testCaseIssuesMapper.deleteByExample(example);
}
public void deleteIssueRelate(IssuesRequest request) {
String caseId = request.getCaseId();
String caseResourceId = request.getCaseResourceId();
String id = request.getId();
TestCaseIssuesExample example = new TestCaseIssuesExample();
example.createCriteria().andTestCaseIdEqualTo(caseId).andIssuesIdEqualTo(id);
example.createCriteria().andResourceIdEqualTo(caseResourceId).andIssuesIdEqualTo(id);
testCaseIssuesMapper.deleteByExample(example);
testCaseIssueService.updateIssuesCount(caseId);
if (request.getIsPlanEdit()) {
testCaseIssueService.updateIssuesCount(caseResourceId);
}
}
public void delete(String id) {
@ -339,8 +333,6 @@ public class IssuesService {
Map<String, String> planMap = testPlans.stream()
.collect(Collectors.toMap(TestPlan::getId, TestPlan::getName));
Project project = projectService.getProjectById(request.getProjectId());
issues.forEach(item -> {
User createUser = userMap.get(item.getCreator());
if (createUser != null) {
@ -353,19 +345,23 @@ public class IssuesService {
example.createCriteria().andIssuesIdEqualTo(item.getId());
List<TestCaseIssues> testCaseIssues = testCaseIssuesMapper.selectByExample(example);
List<String> caseIds = testCaseIssues.stream()
.map(TestCaseIssues::getTestCaseId)
.map(TestCaseIssues::getResourceId)
.collect(Collectors.toList());
item.setCaseIds(caseIds);
item.setCaseCount(testCaseIssues.size());
if (IssuesManagePlatform.Tapd.name().equals(project.getPlatform()) && StringUtils.equals(item.getPlatform(), IssuesManagePlatform.Tapd.name())) {
try {
if (StringUtils.equals(item.getPlatform(), IssuesManagePlatform.Tapd.name())) {
TapdPlatform platform = (TapdPlatform) IssueFactory.createPlatform(item.getPlatform(), request);
List<String> tapdUsers = platform.getTapdUsers(item.getProjectId(), item.getPlatformId());
item.setTapdUsers(tapdUsers);
}
if (IssuesManagePlatform.Zentao.name().equals(project.getPlatform()) && StringUtils.equals(item.getPlatform(), IssuesManagePlatform.Zentao.name())) {
if (StringUtils.equals(item.getPlatform(), IssuesManagePlatform.Zentao.name())) {
ZentaoPlatform platform = (ZentaoPlatform) IssueFactory.createPlatform(item.getPlatform(), request);
platform.getZentaoAssignedAndBuilds(item);
}
} catch (Exception e) {
LogUtil.error(e);
}
});
return issues;
}

View File

@ -6,6 +6,7 @@ import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.IssuesMapper;
import io.metersphere.base.mapper.TestCaseIssuesMapper;
import io.metersphere.base.mapper.TestPlanTestCaseMapper;
import io.metersphere.commons.constants.IssueRefType;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.track.dto.TestCaseDTO;
import io.metersphere.track.request.issues.IssuesRelevanceRequest;
@ -16,6 +17,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
@ -41,13 +43,13 @@ public class TestCaseIssueService {
public void delTestCaseIssues(String testCaseId) {
TestCaseIssuesExample example = new TestCaseIssuesExample();
example.createCriteria().andTestCaseIdEqualTo(testCaseId);
example.createCriteria().andResourceIdEqualTo(testCaseId);
testCaseIssuesMapper.deleteByExample(example);
}
public List<TestCaseDTO> list(IssuesRelevanceRequest request) {
List<String> testCaseIds = getTestCaseIdsByIssuesId(request.getIssuesId());
List<TestCaseDTO> list = testCaseService.getTestCaseByIds(testCaseIds);
List<String> caseIds = getCaseIdsByIssuesId(request.getIssuesId());
List<TestCaseDTO> list = testCaseService.getTestCaseByIds(caseIds);
testCaseService.addProjectName(list);
return list;
}
@ -58,37 +60,56 @@ public class TestCaseIssueService {
return testCaseIssuesMapper.selectByExample(example);
}
public List<String> getTestCaseIdsByIssuesId(String issuesId) {
return getTestCaseIssuesByIssuesId(issuesId).stream()
.map(TestCaseIssues::getTestCaseId)
.collect(Collectors.toList());
/**
* 测试计划的用例获取对应的功能用例
* @param issuesId
* @return
*/
public List<String> getCaseIdsByIssuesId(String issuesId) {
List<TestCaseIssues> testCaseIssueList = getTestCaseIssuesByIssuesId(issuesId);
List<String> caseIds = new ArrayList<>();
testCaseIssueList.forEach(i -> {
if (StringUtils.equals(i.getRefType(), IssueRefType.PLAN_FUNCTIONAL.name())) {
caseIds.add(i.getRefId());
} else {
caseIds.add(i.getResourceId());
}
});
return caseIds;
}
public void relate(IssuesRelevanceRequest request) {
if (StringUtils.isNotBlank(request.getCaseId())) {
if (StringUtils.isNotBlank(request.getCaseResourceId())) {
List<String> issueIds = request.getIssueIds();
if (!CollectionUtils.isEmpty(issueIds)) {
issueIds.forEach(issueId -> {
create(request.getCaseId(), issueId);
relate(request, issueId, request.getCaseResourceId());
});
}
} else if (StringUtils.isNotBlank(request.getIssuesId())) {
List<String> caseIds = request.getTestCaseIds();
if (!CollectionUtils.isEmpty(caseIds)) {
caseIds.forEach(caseId -> {
create(caseId, request.getIssuesId());
List<String> caseResourceIds = request.getCaseResourceIds();
if (!CollectionUtils.isEmpty(caseResourceIds)) {
caseResourceIds.forEach(caseResourceId -> {
relate(request, request.getIssuesId(), caseResourceId);
});
}
}
updateIssuesCount(request.getCaseId());
}
public void updateIssuesCount(String caseId) {
List<IssuesDao> issues = issuesService.getIssues(caseId);
protected void relate(IssuesRelevanceRequest request, String issueId, String caseResourceId) {
if (request.getIsPlanEdit()) {
add(issueId, caseResourceId, request.getRefId(), IssueRefType.PLAN_FUNCTIONAL.name());
updateIssuesCount(request.getCaseResourceId());
} else {
add(issueId, caseResourceId, null, IssueRefType.FUNCTIONAL.name());
}
}
public void updateIssuesCount(String resourceId) {
List<IssuesDao> issues = issuesService.getIssues(resourceId, IssueRefType.PLAN_FUNCTIONAL.name());
int issuesCount = issues.size();
TestPlanTestCaseExample example = new TestPlanTestCaseExample();
example.createCriteria().andCaseIdEqualTo(caseId);
example.createCriteria().andIdEqualTo(resourceId);
TestPlanTestCaseWithBLOBs testPlanTestCase = new TestPlanTestCaseWithBLOBs();
testPlanTestCase.setIssuesCount(issuesCount);
if (!CollectionUtils.isEmpty(issues)) {
@ -97,14 +118,17 @@ public class TestCaseIssueService {
testPlanTestCaseMapper.updateByExampleSelective(testPlanTestCase, example);
}
public void create(String caseId, String issueId) {
public void add(String issuesId, String resourceId, String refId, String refType) {
if (StringUtils.isNotBlank(resourceId)) {
TestCaseIssues testCaseIssues = new TestCaseIssues();
testCaseIssues.setId(UUID.randomUUID().toString());
testCaseIssues.setTestCaseId(caseId);
testCaseIssues.setIssuesId(issueId);
testCaseIssues.setIssuesId(issuesId);
testCaseIssues.setResourceId(resourceId);
testCaseIssues.setRefType(refType);
testCaseIssues.setRefId(refId);
testCaseIssuesMapper.insert(testCaseIssues);
}
}
public String getLogDetails(IssuesRelevanceRequest request) {
TestCaseWithBLOBs bloBs = testCaseService.getTestCase(request.getCaseId());

View File

@ -19,6 +19,7 @@ import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtIssuesMapper;
import io.metersphere.base.mapper.ext.ExtProjectVersionMapper;
import io.metersphere.base.mapper.ext.ExtTestCaseMapper;
import io.metersphere.commons.constants.IssueRefType;
import io.metersphere.commons.constants.TestCaseConstants;
import io.metersphere.commons.constants.TestCaseReviewStatus;
import io.metersphere.commons.constants.UserGroupType;
@ -346,12 +347,12 @@ public class TestCaseService {
testCase.setDemandName(null);
}
if (otherInfoConfig.isRelateIssue()) {
List<IssuesDao> issuesDaos = issuesService.getIssues(oldTestCaseId);
List<IssuesDao> issuesDaos = issuesService.getIssues(oldTestCaseId, IssueRefType.FUNCTIONAL.name());
if (CollectionUtils.isNotEmpty(issuesDaos)) {
issuesDaos.forEach(issue -> {
TestCaseIssues t = new TestCaseIssues();
t.setId(UUID.randomUUID().toString());
t.setTestCaseId(testCase.getId());
t.setResourceId(testCase.getId());
t.setIssuesId(issue.getId());
testCaseIssuesMapper.insertSelective(t);
});
@ -1907,7 +1908,7 @@ public class TestCaseService {
setDefaultOrder(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);
HashMap<String, List<IssuesDao>> issueMap = buildMinderIssueMap(caseIds, IssueRefType.FUNCTIONAL.name());
for (TestCaseDTO item : cases) {
List<IssuesDao> issues = issueMap.get(item.getId());
if (issues != null) {
@ -1917,10 +1918,10 @@ public class TestCaseService {
return cases;
}
public HashMap<String, List<IssuesDao>> buildMinderIssueMap(List<String> caseIds) {
public HashMap<String, List<IssuesDao>> buildMinderIssueMap(List<String> caseIds, String refType) {
HashMap<String, List<IssuesDao>> issueMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(caseIds)) {
List<IssuesDao> issues = extIssuesMapper.getIssueForMinder(caseIds);
List<IssuesDao> issues = extIssuesMapper.getIssueForMinder(caseIds, refType);
for (IssuesDao item : issues) {
List<IssuesDao> list = issueMap.get(item.getCaseId());
if (list == null) {
@ -2010,7 +2011,7 @@ public class TestCaseService {
//关联缺陷
List<String> issuesNames = new LinkedList<>();
TestCaseIssuesExample testCaseIssuesExample = new TestCaseIssuesExample();
testCaseIssuesExample.createCriteria().andTestCaseIdEqualTo(bloBs.getId());
testCaseIssuesExample.createCriteria().andResourceIdEqualTo(bloBs.getId());
List<TestCaseIssues> testCaseIssues = testCaseIssuesMapper.selectByExample(testCaseIssuesExample);
if (CollectionUtils.isNotEmpty(testCaseIssues)) {
List<String> issuesIds = testCaseIssues.stream().map(TestCaseIssues::getIssuesId).collect(Collectors.toList());
@ -2552,7 +2553,7 @@ public class TestCaseService {
TestCaseWithBLOBs tc = getTestCase(caseId);
if (tc != null) {
if (StringUtils.isNotBlank(tc.getRemark()) || StringUtils.isNotBlank(tc.getDemandId()) || CollectionUtils.isNotEmpty(getRelateTest(caseId))
|| CollectionUtils.isNotEmpty(issuesService.getIssues(caseId)) || CollectionUtils.isNotEmpty(getRelationshipCase(caseId, "PRE")) || CollectionUtils.isNotEmpty(getRelationshipCase(caseId, "POST"))
|| CollectionUtils.isNotEmpty(issuesService.getIssues(caseId, IssueRefType.FUNCTIONAL.name())) || CollectionUtils.isNotEmpty(getRelationshipCase(caseId, "PRE")) || CollectionUtils.isNotEmpty(getRelationshipCase(caseId, "POST"))
|| CollectionUtils.isNotEmpty(fileService.getFileMetadataByCaseId(caseId))) {
return true;
}

View File

@ -917,7 +917,7 @@ public class TestPlanService {
List<TestPlanCaseDTO> testPlanTestCases = listTestCaseByPlanId(planId);
List<IssuesDao> issues = new ArrayList<>();
for (TestPlanCaseDTO testCase : testPlanTestCases) {
List<IssuesDao> issue = issuesService.getIssues(testCase.getCaseId());
List<IssuesDao> issue = issuesService.getIssues(testCase.getId(), IssueRefType.PLAN_FUNCTIONAL.name());
if (issue.size() > 0) {
for (IssuesDao i : issue) {
i.setModel(testCase.getNodePath());

View File

@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.commons.constants.IssueRefType;
import io.metersphere.commons.constants.TestPlanTestCaseStatus;
import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.*;
@ -302,10 +303,10 @@ public class TestPlanTestCaseService {
});
request.setOrders(orders);
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);
List<String> caseIds = cases.stream().map(TestPlanCaseDTO::getId).collect(Collectors.toList());
HashMap<String, List<IssuesDao>> issueMap = testCaseService.buildMinderIssueMap(caseIds, IssueRefType.PLAN_FUNCTIONAL.name());
for (TestPlanCaseDTO item : cases) {
List<IssuesDao> issues = issueMap.get(item.getCaseId());
List<IssuesDao> issues = issueMap.get(item.getId());
if (issues != null) {
item.setIssueList(issues);
}

View File

@ -63,6 +63,30 @@ DELIMITER ;
CALL test_personal();
DROP PROCEDURE IF EXISTS test_personal;
-- 测试计划缺陷与用例缺陷分离
ALTER TABLE test_case_issues ADD ref_type varchar(30) DEFAULT 'FUNCTIONAL' NOT NULL;
ALTER TABLE test_case_issues CHANGE test_case_id resource_id varchar(50) NOT NULL;
ALTER TABLE test_case_issues ADD ref_id varchar(50) NULL COMMENT '测试计划的用例所指向的用例的id';
INSERT INTO test_case_issues (id, resource_id, issues_id, ref_id, ref_type)
SELECT uuid(), tptc.id, i.id, tptc.case_id, 'PLAN_FUNCTIONAL'
FROM issues i
INNER JOIN test_case_issues tci
ON tci.issues_id = i.id
INNER JOIN test_plan_test_case tptc
ON tci.resource_id = tptc.case_id AND i.resource_id = tptc.plan_id
DELETE FROM test_case_issues WHERE id IN (
SELECT id FROM (
SELECT tci.id AS id
FROM issues i
INNER JOIN test_case_issues tci
ON tci.issues_id = i.id
INNER JOIN test_plan_test_case tptc
ON tci.resource_id = tptc.case_id AND i.resource_id = tptc.plan_id
) tmp
)
DROP PROCEDURE IF EXISTS project_appl;
DELIMITER //

View File

@ -90,7 +90,10 @@ export default {
return getCurrentProjectID();
}
},
props: ['caseId'],
props: {
caseId: String,
planCaseId: String,
},
created() {
isThirdPartEnable((data) => {
this.isThirdPart = data;
@ -103,14 +106,18 @@ export default {
},
getIssues() {
this.page.condition.projectId = this.projectId;
this.page.condition.caseId = this.caseId;
this.page.condition.caseResourceId = this.getCaseResourceId();
this.page.result = getRelateIssues(this.page);
},
getCaseResourceId() {
return this.planCaseId ? this.planCaseId : this.caseId;
},
save() {
let param = {};
param.caseId = this.caseId;
param.issueIds = Array.from(this.$refs.table.selectRows).map(i => i.id);
param.caseId = this.caseId;
param.caseResourceId = this.getCaseResourceId();
param.isPlanEdit = !!this.planCaseId;
param.refId = this.planCaseId ? this.caseId : null;
testCaseIssueRelate(param, () => {
this.visible = false;
this.$emit('refresh', this.$refs.table.selectRows);

View File

@ -31,7 +31,9 @@
:plan-id="planId"
:is-copy="isCopy"
:read-only="readOnly && !(isTestPlan)"
:case-id="caseId" ref="issue"/>
:plan-case-id="planId ? this.form.id : null"
:case-id="caseId"
ref="issue"/>
</el-tab-pane>
<el-tab-pane :label="$t('commons.relationship.name')" name="relationship">

View File

@ -85,8 +85,18 @@
</span>
</ms-table>
<test-plan-issue-edit :plan-id="planId" :case-id="caseId" @refresh="getIssues" ref="issueEdit"/>
<IssueRelateList :case-id="caseId" @refresh="getIssues" ref="issueRelate"/>
<test-plan-issue-edit
:plan-case-id="planCaseId"
:plan-id="planId"
:case-id="caseId"
@refresh="getIssues"
ref="issueEdit"/>
<IssueRelateList
:plan-case-id="planCaseId"
:case-id="caseId"
@refresh="getIssues"
ref="issueRelate"/>
</div>
</template>
@ -124,7 +134,13 @@ export default {
issueRelateVisible: false
}
},
props: ['caseId', 'readOnly','planId', 'isCopy'],
props: {
planId: String,
caseId: String,
planCaseId: String,
readOnly: Boolean,
isCopy: Boolean,
},
computed: {
issueStatusMap() {
return ISSUE_STATUS_MAP;
@ -172,12 +188,15 @@ export default {
},
getIssues() {
if (!this.isCopy) {
let result = getIssuesByCaseId(this.caseId, this.page);
let result = getIssuesByCaseId(this.planId ? 'PLAN_FUNCTIONAL' : 'FUNCTIONAL', this.getCaseResourceId(), this.page);
if (result) {
this.page.result = result;
}
}
},
getCaseResourceId() {
return this.planId ? this.planCaseId : this.caseId;
},
addIssue() {
if (!this.caseId || this.isCopy) {
this.$warning(this.$t('api_test.automation.save_case_info'));
@ -203,7 +222,7 @@ export default {
}
},
deleteIssue(row) {
this.page.result = deleteIssueRelate({id: row.id, caseId: this.caseId}, () => {
this.page.result = deleteIssueRelate({id: row.id, caseResourceId: this.getCaseResourceId(), isPlanEdit: this.planId ? true : false}, () => {
this.getIssues();
this.$success(this.$t('commons.delete_success'));
});

View File

@ -7,7 +7,7 @@
append-to-body
ref="msEditDialog">
<template v-slot:default="scope">
<issue-edit-detail :is-minder="isMinder" :plan-id="planId" :case-id="caseId" :is-plan="true" @refresh="refresh" @close="handleClose" ref="issueEditDetail"/>
<issue-edit-detail :plan-case-id="planCaseId" :is-minder="isMinder" :plan-id="planId" :case-id="caseId" :is-case-edit="true" @refresh="refresh" @close="handleClose" ref="issueEditDetail"/>
</template>
</ms-edit-dialog>
</template>
@ -31,7 +31,12 @@ export default {
return getCurrentProjectID();
}
},
props: ['caseId', 'planId', 'isMinder'],
props: {
planId: String,
caseId: String,
planCaseId: String,
isMinder: Boolean,
},
methods: {
open(data) {
this.visible = true;

View File

@ -17,8 +17,19 @@
@save="save"
ref="minder"
/>
<IssueRelateList :case-id="getCurCaseId()" @refresh="refreshRelateIssue" ref="issueRelate"/>
<test-plan-issue-edit :is-minder="true" :plan-id="null" :case-id="getCurCaseId()" @refresh="refreshIssue" ref="issueEdit"/>
<IssueRelateList
:case-id="getCurCaseId()"
@refresh="refreshRelateIssue"
ref="issueRelate"/>
<test-plan-issue-edit
:is-minder="true"
:plan-id="null"
:case-id="getCurCaseId()"
@refresh="refreshIssue"
ref="issueEdit"/>
</div>
</template>

View File

@ -14,8 +14,21 @@
@save="save"
ref="minder"
/>
<IssueRelateList :case-id="getCurCaseId()" @refresh="refreshRelateIssue" ref="issueRelate"/>
<test-plan-issue-edit :is-minder="true" :plan-id="planId" :case-id="getCurCaseId()" @refresh="refreshIssue" ref="issueEdit"/>
<IssueRelateList
:plan-case-id="getCurId()"
:case-id="getCurCaseId()"
@refresh="refreshRelateIssue"
ref="issueRelate"/>
<test-plan-issue-edit
:is-minder="true"
:plan-id="planId"
:plan-case-id="getCurId()"
:case-id="getCurCaseId()"
@refresh="refreshIssue"
ref="issueEdit"/>
</div>
</template>
@ -180,6 +193,9 @@ name: "TestPlanMinder",
getCurCaseId() {
return getSelectedNodeData().caseId;
},
getCurId() {
return getSelectedNodeData().id;
},
refreshIssue(issue) {
handleIssueAdd(issue);
},

View File

@ -533,9 +533,9 @@ export function handleMinderIssueDelete(commandName, isPlan) {
nodes.forEach(node => {
let data = node.data;
if (data.type === 'issue') {
let caseId = isPlan ? node.parent.data.caseId : node.parent.data.id
let caseResourceId = node.parent.data.id;
let p = new Promise((resolve) => {
deleteIssueRelate({id: data.id, caseId: caseId}, () => {
deleteIssueRelate({id: data.id, caseResourceId, isPlanEdit: isPlan}, () => {
resolve();
});
});

View File

@ -1,5 +1,5 @@
<template>
<el-main v-loading="result.loading" class="container" :style="isPlan ? '' : 'height: calc(100vh - 62px)'">
<el-main v-loading="result.loading" class="container" :style="isCaseEdit ? '' : 'height: calc(100vh - 62px)'">
<el-scrollbar>
<el-form :model="form" :rules="rules" label-position="right" label-width="80px" ref="form">
@ -61,8 +61,8 @@
</el-col>
</el-row>
<el-form-item v-if="!isPlan">
<test-case-issue-list :test-case-contain-ids="testCaseContainIds" :issues-id="form.id"
<el-form-item v-if="!isCaseEdit">
<test-case-issue-list :issues-id="form.id"
ref="testCaseIssueList"/>
</el-form-item>
@ -89,8 +89,10 @@
</div>
</el-col>
</el-row>
<issue-comment :issues-id="form.id"
@getComments="getComments" ref="issueComment"/>
@getComments="getComments"
ref="issueComment"/>
</el-form>
</el-scrollbar>
@ -159,7 +161,6 @@ export default {
{required: true, message: this.$t('commons.please_fill_content'), trigger: 'blur'},
]
},
testCaseContainIds: new Set(),
url: '',
form: {
title: '',
@ -215,7 +216,7 @@ export default {
};
},
props: {
isPlan: {
isCaseEdit: {
type: Boolean,
default() {
return false;
@ -223,6 +224,7 @@ export default {
},
caseId: String,
planId: String,
planCaseId: String,
isMinder: Boolean,
},
computed: {
@ -301,7 +303,6 @@ export default {
}
},
initEdit(data) {
this.testCaseContainIds = new Set();
if (data) {
Object.assign(this.form, data);
if (!(data.options instanceof Array)) {
@ -361,10 +362,24 @@ export default {
param.projectId = this.projectId;
param.workspaceId = getCurrentWorkspaceId();
buildCustomFields(this.form, param, this.issueTemplate);
if (this.isPlan) {
param.testCaseIds = [this.caseId];
if (this.planId) {
//
if (!this.form.id) {
param.addResourceIds = [this.planCaseId];
param.refId = this.caseId;
param.isPlanEdit = true;
}
} else {
param.testCaseIds = Array.from(this.testCaseContainIds);
if (this.isCaseEdit) {
//
if (!this.form.id) {
param.addResourceIds = [this.caseId];
}
} else {
//
param.addResourceIds = [...this.$refs.testCaseIssueList.addIds];
param.deleteResourceIds = [...this.$refs.testCaseIssueList.deleteIds];
}
}
if (this.planId) {
param.resourceId = this.planId;

View File

@ -52,7 +52,6 @@
<test-case-relate-list
@refresh="initTableData"
@save="handleRelate"
:test-case-contain-ids="testCaseContainIds"
ref="testCaseRelevance"/>
</div>
@ -71,6 +70,8 @@ export default {
return {
result: {},
tableData: [],
deleteIds: new Set(),
addIds: new Set(),
operators: [
{
tip: this.$t('commons.delete'), icon: "el-icon-delete", type: "danger",
@ -81,12 +82,11 @@ export default {
},
props: {
issuesId: String,
testCaseContainIds: Set,
},
methods: {
handleDelete(item, index) {
this.testCaseContainIds.delete(item.id);
this.tableData.splice(index, 1);
this.deleteIds.add(item.id);
},
initTableData() {
this.tableData = [];
@ -96,9 +96,6 @@ export default {
if (this.issuesId) {
this.result = this.$post('test/case/issues/list', condition, response => {
this.tableData = response.data;
this.tableData.forEach(item => {
this.testCaseContainIds.add(item.id);
});
this.$refs.table.reloadTable();
});
}
@ -108,10 +105,9 @@ export default {
},
handleRelate(selectRows) {
let selectData = Array.from(selectRows);
selectData.forEach(item => {
if (item.id) {
this.testCaseContainIds.add(item.id);
}
selectRows.forEach(i => {
this.deleteIds.delete(i.id);
this.addIds.add(i.id);
});
this.tableData.push(...selectData);
},

View File

@ -107,9 +107,6 @@ export default {
selectNodeIds: [],
};
},
props: [
'testCaseContainIds'
],
watch: {
selectNodeIds() {
this.initTableData();
@ -135,7 +132,6 @@ export default {
if (this.projectId) {
this.getProjectNode();
this.condition.projectId = this.projectId;
this.condition.testCaseContainIds = Array.from(this.testCaseContainIds)
this.result = this.$post('/test/case/relate/issue/' + +this.currentPage + '/' + this.pageSize, this.condition, response => {
let data = response.data;
this.total = data.itemCount;

View File

@ -24,9 +24,9 @@ export function getIssues(page) {
});
}
export function getIssuesByCaseId(caseId, page) {
export function getIssuesByCaseId(refType, caseId, page) {
if (caseId) {
return get('issues/get/case/' + caseId, (response) => {
return get('issues/get/case/' + refType + '/' + caseId, (response) => {
page.data = response.data;
buildIssues(page);
});