feat(测试计划): 补充测试计划详情缺陷列表功能

This commit is contained in:
song-cc-rock 2024-05-09 19:41:56 +08:00 committed by 刘瑞斌
parent 0626f5c048
commit da2f95d415
19 changed files with 607 additions and 1228 deletions

View File

@ -1,126 +0,0 @@
package io.metersphere.plan.domain;
import io.metersphere.validation.groups.*;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import lombok.Data;
@Data
public class TestPlanBug implements Serializable {
@Schema(description = "ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_bug.id.not_blank}", groups = {Updated.class})
@Size(min = 1, max = 50, message = "{test_plan_bug.id.length_range}", groups = {Created.class, Updated.class})
private String id;
@Schema(description = "num")
private Long num;
@Schema(description = "测试计划ID;测试计划ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_bug.test_plan_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_bug.test_plan_id.length_range}", groups = {Created.class, Updated.class})
private String testPlanId;
@Schema(description = "接口用例ID;测试用例ID包含功能、接口、场景等", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_bug.case_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_bug.case_id.length_range}", groups = {Created.class, Updated.class})
private String caseId;
@Schema(description = "用例类型;用例类型FUNCTIONAL_CASE/API_TEST_CASE/API_SCENARIO)", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_bug.case_type.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_bug.case_type.length_range}", groups = {Created.class, Updated.class})
private String caseType;
@Schema(description = "缺陷id;缺陷ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan_bug.bug_id.not_blank}", groups = {Created.class})
@Size(min = 1, max = 50, message = "{test_plan_bug.bug_id.length_range}", groups = {Created.class, Updated.class})
private String bugId;
@Schema(description = "创建时间")
private Long createTime;
@Schema(description = "创建人")
private String createUser;
private static final long serialVersionUID = 1L;
public enum Column {
id("id", "id", "VARCHAR", false),
num("num", "num", "BIGINT", false),
testPlanId("test_plan_id", "testPlanId", "VARCHAR", false),
caseId("case_id", "caseId", "VARCHAR", false),
caseType("case_type", "caseType", "VARCHAR", false),
bugId("bug_id", "bugId", "VARCHAR", false),
createTime("create_time", "createTime", "BIGINT", false),
createUser("create_user", "createUser", "VARCHAR", false);
private static final String BEGINNING_DELIMITER = "`";
private static final String ENDING_DELIMITER = "`";
private final String column;
private final boolean isColumnNameDelimited;
private final String javaProperty;
private final String jdbcType;
public String value() {
return this.column;
}
public String getValue() {
return this.column;
}
public String getJavaProperty() {
return this.javaProperty;
}
public String getJdbcType() {
return this.jdbcType;
}
Column(String column, String javaProperty, String jdbcType, boolean isColumnNameDelimited) {
this.column = column;
this.javaProperty = javaProperty;
this.jdbcType = jdbcType;
this.isColumnNameDelimited = isColumnNameDelimited;
}
public String desc() {
return this.getEscapedColumnName() + " DESC";
}
public String asc() {
return this.getEscapedColumnName() + " ASC";
}
public static Column[] excludes(Column ... excludes) {
ArrayList<Column> columns = new ArrayList<>(Arrays.asList(Column.values()));
if (excludes != null && excludes.length > 0) {
columns.removeAll(new ArrayList<>(Arrays.asList(excludes)));
}
return columns.toArray(new Column[]{});
}
public static Column[] all() {
return Column.values();
}
public String getEscapedColumnName() {
if (this.isColumnNameDelimited) {
return new StringBuilder().append(BEGINNING_DELIMITER).append(this.column).append(ENDING_DELIMITER).toString();
} else {
return this.column;
}
}
public String getAliasedEscapedColumnName() {
return this.getEscapedColumnName();
}
}
}

View File

@ -1,740 +0,0 @@
package io.metersphere.plan.domain;
import java.util.ArrayList;
import java.util.List;
public class TestPlanBugExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public TestPlanBugExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andNumIsNull() {
addCriterion("num is null");
return (Criteria) this;
}
public Criteria andNumIsNotNull() {
addCriterion("num is not null");
return (Criteria) this;
}
public Criteria andNumEqualTo(Long value) {
addCriterion("num =", value, "num");
return (Criteria) this;
}
public Criteria andNumNotEqualTo(Long value) {
addCriterion("num <>", value, "num");
return (Criteria) this;
}
public Criteria andNumGreaterThan(Long value) {
addCriterion("num >", value, "num");
return (Criteria) this;
}
public Criteria andNumGreaterThanOrEqualTo(Long value) {
addCriterion("num >=", value, "num");
return (Criteria) this;
}
public Criteria andNumLessThan(Long value) {
addCriterion("num <", value, "num");
return (Criteria) this;
}
public Criteria andNumLessThanOrEqualTo(Long value) {
addCriterion("num <=", value, "num");
return (Criteria) this;
}
public Criteria andNumIn(List<Long> values) {
addCriterion("num in", values, "num");
return (Criteria) this;
}
public Criteria andNumNotIn(List<Long> values) {
addCriterion("num not in", values, "num");
return (Criteria) this;
}
public Criteria andNumBetween(Long value1, Long value2) {
addCriterion("num between", value1, value2, "num");
return (Criteria) this;
}
public Criteria andNumNotBetween(Long value1, Long value2) {
addCriterion("num not between", value1, value2, "num");
return (Criteria) this;
}
public Criteria andTestPlanIdIsNull() {
addCriterion("test_plan_id is null");
return (Criteria) this;
}
public Criteria andTestPlanIdIsNotNull() {
addCriterion("test_plan_id is not null");
return (Criteria) this;
}
public Criteria andTestPlanIdEqualTo(String value) {
addCriterion("test_plan_id =", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotEqualTo(String value) {
addCriterion("test_plan_id <>", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdGreaterThan(String value) {
addCriterion("test_plan_id >", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdGreaterThanOrEqualTo(String value) {
addCriterion("test_plan_id >=", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdLessThan(String value) {
addCriterion("test_plan_id <", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdLessThanOrEqualTo(String value) {
addCriterion("test_plan_id <=", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdLike(String value) {
addCriterion("test_plan_id like", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotLike(String value) {
addCriterion("test_plan_id not like", value, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdIn(List<String> values) {
addCriterion("test_plan_id in", values, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotIn(List<String> values) {
addCriterion("test_plan_id not in", values, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdBetween(String value1, String value2) {
addCriterion("test_plan_id between", value1, value2, "testPlanId");
return (Criteria) this;
}
public Criteria andTestPlanIdNotBetween(String value1, String value2) {
addCriterion("test_plan_id not between", value1, value2, "testPlanId");
return (Criteria) this;
}
public Criteria andCaseIdIsNull() {
addCriterion("case_id is null");
return (Criteria) this;
}
public Criteria andCaseIdIsNotNull() {
addCriterion("case_id is not null");
return (Criteria) this;
}
public Criteria andCaseIdEqualTo(String value) {
addCriterion("case_id =", value, "caseId");
return (Criteria) this;
}
public Criteria andCaseIdNotEqualTo(String value) {
addCriterion("case_id <>", value, "caseId");
return (Criteria) this;
}
public Criteria andCaseIdGreaterThan(String value) {
addCriterion("case_id >", value, "caseId");
return (Criteria) this;
}
public Criteria andCaseIdGreaterThanOrEqualTo(String value) {
addCriterion("case_id >=", value, "caseId");
return (Criteria) this;
}
public Criteria andCaseIdLessThan(String value) {
addCriterion("case_id <", value, "caseId");
return (Criteria) this;
}
public Criteria andCaseIdLessThanOrEqualTo(String value) {
addCriterion("case_id <=", value, "caseId");
return (Criteria) this;
}
public Criteria andCaseIdLike(String value) {
addCriterion("case_id like", value, "caseId");
return (Criteria) this;
}
public Criteria andCaseIdNotLike(String value) {
addCriterion("case_id not like", value, "caseId");
return (Criteria) this;
}
public Criteria andCaseIdIn(List<String> values) {
addCriterion("case_id in", values, "caseId");
return (Criteria) this;
}
public Criteria andCaseIdNotIn(List<String> values) {
addCriterion("case_id not in", values, "caseId");
return (Criteria) this;
}
public Criteria andCaseIdBetween(String value1, String value2) {
addCriterion("case_id between", value1, value2, "caseId");
return (Criteria) this;
}
public Criteria andCaseIdNotBetween(String value1, String value2) {
addCriterion("case_id not between", value1, value2, "caseId");
return (Criteria) this;
}
public Criteria andCaseTypeIsNull() {
addCriterion("case_type is null");
return (Criteria) this;
}
public Criteria andCaseTypeIsNotNull() {
addCriterion("case_type is not null");
return (Criteria) this;
}
public Criteria andCaseTypeEqualTo(String value) {
addCriterion("case_type =", value, "caseType");
return (Criteria) this;
}
public Criteria andCaseTypeNotEqualTo(String value) {
addCriterion("case_type <>", value, "caseType");
return (Criteria) this;
}
public Criteria andCaseTypeGreaterThan(String value) {
addCriterion("case_type >", value, "caseType");
return (Criteria) this;
}
public Criteria andCaseTypeGreaterThanOrEqualTo(String value) {
addCriterion("case_type >=", value, "caseType");
return (Criteria) this;
}
public Criteria andCaseTypeLessThan(String value) {
addCriterion("case_type <", value, "caseType");
return (Criteria) this;
}
public Criteria andCaseTypeLessThanOrEqualTo(String value) {
addCriterion("case_type <=", value, "caseType");
return (Criteria) this;
}
public Criteria andCaseTypeLike(String value) {
addCriterion("case_type like", value, "caseType");
return (Criteria) this;
}
public Criteria andCaseTypeNotLike(String value) {
addCriterion("case_type not like", value, "caseType");
return (Criteria) this;
}
public Criteria andCaseTypeIn(List<String> values) {
addCriterion("case_type in", values, "caseType");
return (Criteria) this;
}
public Criteria andCaseTypeNotIn(List<String> values) {
addCriterion("case_type not in", values, "caseType");
return (Criteria) this;
}
public Criteria andCaseTypeBetween(String value1, String value2) {
addCriterion("case_type between", value1, value2, "caseType");
return (Criteria) this;
}
public Criteria andCaseTypeNotBetween(String value1, String value2) {
addCriterion("case_type not between", value1, value2, "caseType");
return (Criteria) this;
}
public Criteria andBugIdIsNull() {
addCriterion("bug_id is null");
return (Criteria) this;
}
public Criteria andBugIdIsNotNull() {
addCriterion("bug_id is not null");
return (Criteria) this;
}
public Criteria andBugIdEqualTo(String value) {
addCriterion("bug_id =", value, "bugId");
return (Criteria) this;
}
public Criteria andBugIdNotEqualTo(String value) {
addCriterion("bug_id <>", value, "bugId");
return (Criteria) this;
}
public Criteria andBugIdGreaterThan(String value) {
addCriterion("bug_id >", value, "bugId");
return (Criteria) this;
}
public Criteria andBugIdGreaterThanOrEqualTo(String value) {
addCriterion("bug_id >=", value, "bugId");
return (Criteria) this;
}
public Criteria andBugIdLessThan(String value) {
addCriterion("bug_id <", value, "bugId");
return (Criteria) this;
}
public Criteria andBugIdLessThanOrEqualTo(String value) {
addCriterion("bug_id <=", value, "bugId");
return (Criteria) this;
}
public Criteria andBugIdLike(String value) {
addCriterion("bug_id like", value, "bugId");
return (Criteria) this;
}
public Criteria andBugIdNotLike(String value) {
addCriterion("bug_id not like", value, "bugId");
return (Criteria) this;
}
public Criteria andBugIdIn(List<String> values) {
addCriterion("bug_id in", values, "bugId");
return (Criteria) this;
}
public Criteria andBugIdNotIn(List<String> values) {
addCriterion("bug_id not in", values, "bugId");
return (Criteria) this;
}
public Criteria andBugIdBetween(String value1, String value2) {
addCriterion("bug_id between", value1, value2, "bugId");
return (Criteria) this;
}
public Criteria andBugIdNotBetween(String value1, String value2) {
addCriterion("bug_id not between", value1, value2, "bugId");
return (Criteria) this;
}
public Criteria andCreateTimeIsNull() {
addCriterion("create_time is null");
return (Criteria) this;
}
public Criteria andCreateTimeIsNotNull() {
addCriterion("create_time is not null");
return (Criteria) this;
}
public Criteria andCreateTimeEqualTo(Long value) {
addCriterion("create_time =", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotEqualTo(Long value) {
addCriterion("create_time <>", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThan(Long value) {
addCriterion("create_time >", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("create_time >=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThan(Long value) {
addCriterion("create_time <", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThanOrEqualTo(Long value) {
addCriterion("create_time <=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeIn(List<Long> values) {
addCriterion("create_time in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotIn(List<Long> values) {
addCriterion("create_time not in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeBetween(Long value1, Long value2) {
addCriterion("create_time between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotBetween(Long value1, Long value2) {
addCriterion("create_time not between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andCreateUserIsNull() {
addCriterion("create_user is null");
return (Criteria) this;
}
public Criteria andCreateUserIsNotNull() {
addCriterion("create_user is not null");
return (Criteria) this;
}
public Criteria andCreateUserEqualTo(String value) {
addCriterion("create_user =", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotEqualTo(String value) {
addCriterion("create_user <>", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserGreaterThan(String value) {
addCriterion("create_user >", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserGreaterThanOrEqualTo(String value) {
addCriterion("create_user >=", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLessThan(String value) {
addCriterion("create_user <", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLessThanOrEqualTo(String value) {
addCriterion("create_user <=", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserLike(String value) {
addCriterion("create_user like", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotLike(String value) {
addCriterion("create_user not like", value, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserIn(List<String> values) {
addCriterion("create_user in", values, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotIn(List<String> values) {
addCriterion("create_user not in", values, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserBetween(String value1, String value2) {
addCriterion("create_user between", value1, value2, "createUser");
return (Criteria) this;
}
public Criteria andCreateUserNotBetween(String value1, String value2) {
addCriterion("create_user not between", value1, value2, "createUser");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -1,34 +0,0 @@
package io.metersphere.plan.mapper;
import io.metersphere.plan.domain.TestPlanBug;
import io.metersphere.plan.domain.TestPlanBugExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface TestPlanBugMapper {
long countByExample(TestPlanBugExample example);
int deleteByExample(TestPlanBugExample example);
int deleteByPrimaryKey(String id);
int insert(TestPlanBug record);
int insertSelective(TestPlanBug record);
List<TestPlanBug> selectByExample(TestPlanBugExample example);
TestPlanBug selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") TestPlanBug record, @Param("example") TestPlanBugExample example);
int updateByExample(@Param("record") TestPlanBug record, @Param("example") TestPlanBugExample example);
int updateByPrimaryKeySelective(TestPlanBug record);
int updateByPrimaryKey(TestPlanBug record);
int batchInsert(@Param("list") List<TestPlanBug> list);
int batchInsertSelective(@Param("list") List<TestPlanBug> list, @Param("selective") TestPlanBug.Column ... selective);
}

View File

@ -1,306 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.plan.mapper.TestPlanBugMapper">
<resultMap id="BaseResultMap" type="io.metersphere.plan.domain.TestPlanBug">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="num" jdbcType="BIGINT" property="num" />
<result column="test_plan_id" jdbcType="VARCHAR" property="testPlanId" />
<result column="case_id" jdbcType="VARCHAR" property="caseId" />
<result column="case_type" jdbcType="VARCHAR" property="caseType" />
<result column="bug_id" jdbcType="VARCHAR" property="bugId" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="create_user" jdbcType="VARCHAR" property="createUser" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, num, test_plan_id, case_id, case_type, bug_id, create_time, create_user
</sql>
<select id="selectByExample" parameterType="io.metersphere.plan.domain.TestPlanBugExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from test_plan_bug
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from test_plan_bug
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from test_plan_bug
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.plan.domain.TestPlanBugExample">
delete from test_plan_bug
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.plan.domain.TestPlanBug">
insert into test_plan_bug (id, num, test_plan_id,
case_id, case_type, bug_id,
create_time, create_user)
values (#{id,jdbcType=VARCHAR}, #{num,jdbcType=BIGINT}, #{testPlanId,jdbcType=VARCHAR},
#{caseId,jdbcType=VARCHAR}, #{caseType,jdbcType=VARCHAR}, #{bugId,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{createUser,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.plan.domain.TestPlanBug">
insert into test_plan_bug
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="num != null">
num,
</if>
<if test="testPlanId != null">
test_plan_id,
</if>
<if test="caseId != null">
case_id,
</if>
<if test="caseType != null">
case_type,
</if>
<if test="bugId != null">
bug_id,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="createUser != null">
create_user,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="num != null">
#{num,jdbcType=BIGINT},
</if>
<if test="testPlanId != null">
#{testPlanId,jdbcType=VARCHAR},
</if>
<if test="caseId != null">
#{caseId,jdbcType=VARCHAR},
</if>
<if test="caseType != null">
#{caseType,jdbcType=VARCHAR},
</if>
<if test="bugId != null">
#{bugId,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="createUser != null">
#{createUser,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.plan.domain.TestPlanBugExample" resultType="java.lang.Long">
select count(*) from test_plan_bug
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update test_plan_bug
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.num != null">
num = #{record.num,jdbcType=BIGINT},
</if>
<if test="record.testPlanId != null">
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
</if>
<if test="record.caseId != null">
case_id = #{record.caseId,jdbcType=VARCHAR},
</if>
<if test="record.caseType != null">
case_type = #{record.caseType,jdbcType=VARCHAR},
</if>
<if test="record.bugId != null">
bug_id = #{record.bugId,jdbcType=VARCHAR},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update test_plan_bug
set id = #{record.id,jdbcType=VARCHAR},
num = #{record.num,jdbcType=BIGINT},
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
case_id = #{record.caseId,jdbcType=VARCHAR},
case_type = #{record.caseType,jdbcType=VARCHAR},
bug_id = #{record.bugId,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
create_user = #{record.createUser,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.plan.domain.TestPlanBug">
update test_plan_bug
<set>
<if test="num != null">
num = #{num,jdbcType=BIGINT},
</if>
<if test="testPlanId != null">
test_plan_id = #{testPlanId,jdbcType=VARCHAR},
</if>
<if test="caseId != null">
case_id = #{caseId,jdbcType=VARCHAR},
</if>
<if test="caseType != null">
case_type = #{caseType,jdbcType=VARCHAR},
</if>
<if test="bugId != null">
bug_id = #{bugId,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="createUser != null">
create_user = #{createUser,jdbcType=VARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.plan.domain.TestPlanBug">
update test_plan_bug
set num = #{num,jdbcType=BIGINT},
test_plan_id = #{testPlanId,jdbcType=VARCHAR},
case_id = #{caseId,jdbcType=VARCHAR},
case_type = #{caseType,jdbcType=VARCHAR},
bug_id = #{bugId,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
create_user = #{createUser,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into test_plan_bug
(id, num, test_plan_id, case_id, case_type, bug_id, create_time, create_user)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.num,jdbcType=BIGINT}, #{item.testPlanId,jdbcType=VARCHAR},
#{item.caseId,jdbcType=VARCHAR}, #{item.caseType,jdbcType=VARCHAR}, #{item.bugId,jdbcType=VARCHAR},
#{item.createTime,jdbcType=BIGINT}, #{item.createUser,jdbcType=VARCHAR})
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
insert into test_plan_bug (
<foreach collection="selective" item="column" separator=",">
${column.escapedColumnName}
</foreach>
)
values
<foreach collection="list" item="item" separator=",">
(
<foreach collection="selective" item="column" separator=",">
<if test="'id'.toString() == column.value">
#{item.id,jdbcType=VARCHAR}
</if>
<if test="'num'.toString() == column.value">
#{item.num,jdbcType=BIGINT}
</if>
<if test="'test_plan_id'.toString() == column.value">
#{item.testPlanId,jdbcType=VARCHAR}
</if>
<if test="'case_id'.toString() == column.value">
#{item.caseId,jdbcType=VARCHAR}
</if>
<if test="'case_type'.toString() == column.value">
#{item.caseType,jdbcType=VARCHAR}
</if>
<if test="'bug_id'.toString() == column.value">
#{item.bugId,jdbcType=VARCHAR}
</if>
<if test="'create_time'.toString() == column.value">
#{item.createTime,jdbcType=BIGINT}
</if>
<if test="'create_user'.toString() == column.value">
#{item.createUser,jdbcType=VARCHAR}
</if>
</foreach>
)
</foreach>
</insert>
</mapper>

View File

@ -24,6 +24,7 @@ CREATE INDEX idx_num ON test_plan_functional_case(num);
ALTER TABLE test_resource_pool DROP COLUMN api_test; ALTER TABLE test_resource_pool DROP COLUMN api_test;
ALTER TABLE test_resource_pool DROP COLUMN load_test; ALTER TABLE test_resource_pool DROP COLUMN load_test;
ALTER TABLE test_resource_pool DROP COLUMN ui_test; ALTER TABLE test_resource_pool DROP COLUMN ui_test;
DROP TABLE test_plan_bug;
CREATE TABLE IF NOT EXISTS test_plan_allocation CREATE TABLE IF NOT EXISTS test_plan_allocation

View File

@ -26,6 +26,7 @@ import io.metersphere.system.domain.ServiceIntegration;
import io.metersphere.system.service.PlatformPluginService; import io.metersphere.system.service.PlatformPluginService;
import io.metersphere.system.service.PluginLoadService; import io.metersphere.system.service.PluginLoadService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils; 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;
@ -33,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -41,6 +43,8 @@ public class BugCommonService {
@Resource @Resource
private FileService fileService; private FileService fileService;
@Resource @Resource
private BugStatusService bugStatusService;
@Resource
private BugCommentMapper bugCommentMapper; private BugCommentMapper bugCommentMapper;
@Resource @Resource
private BugContentMapper bugContentMapper; private BugContentMapper bugContentMapper;
@ -172,4 +176,30 @@ public class BugCommonService {
followerExample.createCriteria().andBugIdIn(bugIds); followerExample.createCriteria().andBugIdIn(bugIds);
bugFollowerMapper.deleteByExample(followerExample); bugFollowerMapper.deleteByExample(followerExample);
} }
/**
* 获取状态集合
* @param projectId 项目ID
* @return 处理人集合
*/
public Map<String, String> getAllHandlerMap(String projectId) {
// 缺陷表头处理人选项
List<SelectOption> headerOptions = getHeaderHandlerOption(projectId);
List<SelectOption> localOptions = getLocalHandlerOption(projectId);
List<SelectOption> allHandleOption = ListUtils.union(headerOptions, localOptions).stream().distinct().toList();
return allHandleOption.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText));
}
/**
* 获取状态选项
* @param projectId 项目ID
* @return 状态集合
*/
public Map<String, String> getAllStatusMap(String projectId) {
// 缺陷表头状态选项
List<SelectOption> headerOptions = bugStatusService.getHeaderStatusOption(projectId);
List<SelectOption> localOptions = bugStatusService.getAllLocalStatusOptions(projectId);
List<SelectOption> allStatusOption = ListUtils.union(headerOptions, localOptions).stream().distinct().toList();
return allStatusOption.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText));
}
} }

View File

@ -1245,21 +1245,13 @@ public class BugService {
List<String> ids = bugs.stream().map(BugDTO::getId).toList(); List<String> ids = bugs.stream().map(BugDTO::getId).toList();
List<BugCustomFieldDTO> customFields = extBugCustomFieldMapper.getBugAllCustomFields(ids, projectId); List<BugCustomFieldDTO> customFields = extBugCustomFieldMapper.getBugAllCustomFields(ids, projectId);
Map<String, List<BugCustomFieldDTO>> customFieldMap = customFields.stream().collect(Collectors.groupingBy(BugCustomFieldDTO::getBugId)); Map<String, List<BugCustomFieldDTO>> customFieldMap = customFields.stream().collect(Collectors.groupingBy(BugCustomFieldDTO::getBugId));
// 表头处理人选项 Map<String, String> allHandlerMap = bugCommonService.getAllHandlerMap(projectId);
List<SelectOption> handleUserOption = bugCommonService.getHeaderHandlerOption(projectId); Map<String, String> allStatusMap = bugCommonService.getAllStatusMap(projectId);
Map<String, String> handleMap = handleUserOption.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText));
List<SelectOption> localHandlerOption = bugCommonService.getLocalHandlerOption(projectId);
Map<String, String> localHandleMap = localHandlerOption.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText));
// 表头状态选项
List<SelectOption> statusOption = bugStatusService.getHeaderStatusOption(projectId);
Map<String, String> statusMap = statusOption.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText));
List<SelectOption> localStatusOptions = bugStatusService.getAllLocalStatusOptions(projectId);
Map<String, String> localStatusMap = localStatusOptions.stream().collect(Collectors.toMap(SelectOption::getValue, SelectOption::getText));
bugs.forEach(bug -> { bugs.forEach(bug -> {
bug.setCustomFields(customFieldMap.get(bug.getId())); bug.setCustomFields(customFieldMap.get(bug.getId()));
// 解析处理人, 状态 // 解析处理人, 状态
bug.setHandleUserName(StringUtils.isBlank(handleMap.get(bug.getHandleUser())) ? localHandleMap.get(bug.getHandleUser()) : handleMap.get(bug.getHandleUser())); bug.setHandleUserName(allHandlerMap.get(bug.getHandleUser()));
bug.setStatusName(StringUtils.isBlank(statusMap.get(bug.getStatus())) ? localStatusMap.get(bug.getStatus()) : statusMap.get(bug.getStatus())); bug.setStatusName(allStatusMap.get(bug.getStatus()));
}); });
return bugs; return bugs;
} }

View File

@ -36,6 +36,11 @@
<type>test-jar</type> <type>test-jar</type>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>io.metersphere</groupId>
<artifactId>metersphere-bug-management</artifactId>
<version>${revision}</version>
</dependency>
</dependencies> </dependencies>

View File

@ -0,0 +1,40 @@
package io.metersphere.plan.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.plan.dto.request.TestPlanBugPageRequest;
import io.metersphere.plan.dto.response.TestPlanBugPageResponse;
import io.metersphere.plan.service.TestPlanBugService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Tag(name = "测试计划-详情-缺陷列表")
@RestController
@RequestMapping("/test-plan/bug")
public class TestPlanBugController {
@Resource
private TestPlanBugService testPlanBugService;
@PostMapping("/page")
@Operation(summary = "缺陷列表-分页查询")
@RequiresPermissions(PermissionConstants.TEST_PLAN_READ)
public Pager<List<TestPlanBugPageResponse>> page(@Validated @RequestBody TestPlanBugPageRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "b.create_time desc");
return PageUtils.setPageInfo(page, testPlanBugService.page(request));
}
}

View File

@ -0,0 +1,17 @@
package io.metersphere.plan.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class TestPlanBugCaseDTO {
@Schema(description = "用例ID")
private String id;
@Schema(description = "缺陷ID")
private String bugId;
@Schema(description = "用例名称")
private String name;
}

View File

@ -0,0 +1,20 @@
package io.metersphere.plan.dto.request;
import io.metersphere.system.dto.sdk.BasePageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class TestPlanBugPageRequest extends BasePageRequest {
@Schema(description = "计划ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.id.not_blank}")
private String planId;
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{test_plan.project_id.not_blank}")
private String projectId;
}

View File

@ -0,0 +1,30 @@
package io.metersphere.plan.dto.response;
import io.metersphere.plan.dto.TestPlanBugCaseDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = false)
public class TestPlanBugPageResponse {
@Schema(description = "缺陷ID")
private String id;
@Schema(description = "缺陷业务ID")
private String num;
@Schema(description = "缺陷标题")
private String title;
@Schema(description = "关联用例集合")
private List<TestPlanBugCaseDTO> relateCase;
@Schema(description = "处理人")
private String handleUser;
@Schema(description = "状态")
private String status;
@Schema(description = "创建人")
private String createUser;
@Schema(description = "创建时间")
private Long createTime;
}

View File

@ -0,0 +1,26 @@
package io.metersphere.plan.mapper;
import io.metersphere.plan.dto.TestPlanBugCaseDTO;
import io.metersphere.plan.dto.request.TestPlanBugPageRequest;
import io.metersphere.plan.dto.response.TestPlanBugPageResponse;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface ExtTestPlanBugMapper {
/**
* 查询计划-关联缺陷列表
* @param request 请求参数
* @return 缺陷列表
*/
List<TestPlanBugPageResponse> list(@Param("request") TestPlanBugPageRequest request);
/**
* 根据缺陷ID集合获取计划下缺陷关联的用例集合
* @param bugIds 缺陷ID集合
* @param planId 计划ID
* @return 用例集合
*/
List<TestPlanBugCaseDTO> getBugRelatedCase(@Param("ids") List<String> bugIds, @Param("planId") String planId);
}

View File

@ -0,0 +1,236 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.plan.mapper.ExtTestPlanBugMapper">
<select id="list" parameterType="io.metersphere.plan.dto.request.TestPlanBugPageRequest" resultType="io.metersphere.plan.dto.response.TestPlanBugPageResponse">
select b.id as id, b.num as num, b.title as title, b.handle_user handleUser, b.status as status, b.create_user createUser, b.create_time createTime
from bug_relation_case brc join bug b on brc.bug_id = b.id
where brc.test_plan_id = #{request.planId}
<if test="request.keyword != null and request.keyword != ''">
and (
b.title like concat('%', #{request.keyword},'%')
or b.num like concat('%', #{request.keyword},'%')
or b.tags like concat('%', #{request.keyword}, '%')
)
</if>
<include refid="filters">
<property name="filter" value="request.filter"/>
</include>
<include refid="combine">
<property name="condition" value="request.combine"/>
<property name="searchMode" value="request.searchMode"/>
<property name="combineTag" value="request.combine.tag"/>
</include>
group by brc.bug_id
</select>
<select id="getBugRelatedCase" resultType="io.metersphere.plan.dto.TestPlanBugCaseDTO">
select brc.test_plan_case_id as id, brc.bug_id as bugId, fc.name as name
from bug_relation_case brc
join functional_case fc on brc.test_plan_case_id = fc.id
# 后续会有其他用例, 根据关联用例类型, 取不同用例表
where brc.test_plan_id = #{planId}
and brc.bug_id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
<sql id="filters">
<if test="${filter} != null and ${filter}.size() > 0">
<foreach collection="${filter}.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<!-- 处理人 -->
<when test="key == 'handleUser'">
and b.handle_user in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</when>
<!-- 状态 -->
<when test="key=='status'">
and b.status in
<include refid="io.metersphere.system.mapper.BaseMapper.filterInWrapper"/>
</when>
</choose>
</if>
</foreach>
</if>
</sql>
<sql id="combine">
<if test="request.combine != null">
and (
<!-- 任意/所有拼接 -->
<include refid="prefixMode">
<property name="searchMode" value="${searchMode}"/>
</include>
<!-- ID -->
<if test='${condition}.num != null'>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
b.num
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.num"/>
</include>
</if>
<!-- 名称 -->
<if test='${condition}.title != null'>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
b.title
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.title"/>
</include>
</if>
<!-- 所属平台 -->
<if test='${condition}.platform != null'>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
b.platform
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.platform"/>
</include>
</if>
<!-- 处理人 -->
<if test='${condition}.handleUser != null'>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
b.handle_user
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.handleUser"/>
</include>
</if>
<!-- 状态 -->
<if test='${condition}.status != null'>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
b.status
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.status"/>
</include>
</if>
<!-- 创建人 -->
<if test='${condition}.createUser != null'>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
b.create_user
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.createUser"/>
</include>
</if>
<!-- 创建时间 -->
<if test='${condition}.createTime != null'>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
b.create_time
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="${condition}.createTime"/>
</include>
</if>
<!-- 标签 -->
<if test='${condition}.tags != null'>
<include refid="queryTag">
<property name="searchMode" value="${searchMode}"/>
<property name="combineTag" value="${condition}.tags"/>
</include>
</if>
<!-- 自定义字段 -->
<if test="${condition}.customs != null and ${condition}.customs.size() > 0">
<foreach collection="${condition}.customs" item="custom" separator="" open="" close="">
<if test="custom.value != ''">
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
<if test='custom.operator == "not like" or custom.operator == "not in"'>
b.id not in (
</if>
<if test='custom.operator != "not like" and custom.operator != "not in"'>
b.id in (
</if>
select bug_id from bug_custom_field where field_id = #{custom.id} and
<choose>
<when test="custom.type == 'array'">
<foreach collection="custom.value" item="val" separator="or" open="(" close=")">
JSON_CONTAINS(`value`, JSON_ARRAY(#{val}))
</foreach>
</when>
<when test="custom.type == 'time'">
left(replace(unix_timestamp(trim(both '"' from `value`)), '.', ''), 13)
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="custom"/>
</include>
</when>
<otherwise>
trim(both '"' from `value`)
<include refid="io.metersphere.system.mapper.BaseMapper.condition">
<property name="object" value="custom"/>
</include>
</otherwise>
</choose>
)
</if>
</foreach>
</if>
)
</if>
</sql>
<sql id="prefixMode">
<choose>
<when test='${searchMode} == "AND"'>
1 = 1
</when>
<when test='${searchMode} == "OR"'>
1 = 2
</when>
</choose>
</sql>
<sql id="queryType">
<choose>
<when test='${searchMode} == "AND"'>
and
</when>
<when test='${searchMode} == "OR"'>
or
</when>
</choose>
</sql>
<sql id="queryTag">
<!-- 不包含 -->
<if test='${combineTag}.value.size() > 0 and ${combineTag}.operator == "not like"'>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
(
b.tags is null or b.tags = '[]' or
<foreach collection="${combineTag}.value" item="tag" separator="and" open="(" close=")">
!JSON_CONTAINS(b.tags, JSON_ARRAY(#{tag}))
</foreach>
)
</if>
<!-- 包含 -->
<if test='${combineTag}.value.size() > 0 and ${combineTag}.operator == "like"'>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
<foreach collection="${combineTag}.value" item="tag" separator="or" open="(" close=")">
JSON_CONTAINS(b.tags, JSON_ARRAY(#{tag}))
</foreach>
</if>
<!---->
<if test='${combineTag}.operator == "is null"'>
<include refid="queryType">
<property name="searchMode" value="${searchMode}"/>
</include>
(b.tags is null or b.tags = '[]')
</if>
</sql>
</mapper>

View File

@ -317,7 +317,7 @@
<select id="selectBaseInfoByIds" resultType="io.metersphere.plan.domain.TestPlan"> <select id="selectBaseInfoByIds" resultType="io.metersphere.plan.domain.TestPlan">
SELECT SELECT
t.id,t.name,t.type,t.project_id t.id,t.name,t.type,t.project_id,t.type
FROM test_plan t FROM test_plan t
WHERE t.id IN WHERE t.id IN
<foreach collection="list" item="item" open="(" separator="," close=")"> <foreach collection="list" item="item" open="(" separator="," close=")">

View File

@ -1,28 +1,71 @@
package io.metersphere.plan.service; package io.metersphere.plan.service;
import io.metersphere.plan.domain.TestPlanBugExample; import io.metersphere.bug.domain.BugRelationCase;
import io.metersphere.plan.mapper.TestPlanBugMapper; import io.metersphere.bug.domain.BugRelationCaseExample;
import io.metersphere.bug.mapper.BugRelationCaseMapper;
import io.metersphere.bug.service.BugCommonService;
import io.metersphere.plan.dto.TestPlanBugCaseDTO;
import io.metersphere.plan.dto.request.TestPlanBugPageRequest;
import io.metersphere.plan.dto.response.TestPlanBugPageResponse;
import io.metersphere.plan.mapper.ExtTestPlanBugMapper;
import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.mapper.BaseUserMapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.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 java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public class TestPlanBugService extends TestPlanResourceService { public class TestPlanBugService extends TestPlanResourceService {
@Resource @Resource
private TestPlanBugMapper testPlanBugMapper; private BaseUserMapper baseUserMapper;
@Resource
private ExtTestPlanBugMapper extTestPlanBugMapper;
@Resource
private BugRelationCaseMapper bugRelationCaseMapper;
@Resource
private BugCommonService bugCommonService;
public List<TestPlanBugPageResponse> page(TestPlanBugPageRequest request) {
List<TestPlanBugPageResponse> bugList = extTestPlanBugMapper.list(request);
if (CollectionUtils.isEmpty(bugList)) {
return new ArrayList<>();
}
parseCustomField(bugList, request.getProjectId());
return buildBugRelatedListExtraInfo(bugList, request.getPlanId());
}
@Override @Override
public int deleteBatchByTestPlanId(List<String> testPlanIdList) { public int deleteBatchByTestPlanId(List<String> testPlanIdList) {
if (CollectionUtils.isEmpty(testPlanIdList)) { BugRelationCaseExample example = new BugRelationCaseExample();
return 0;
}
TestPlanBugExample example = new TestPlanBugExample();
example.createCriteria().andTestPlanIdIn(testPlanIdList); example.createCriteria().andTestPlanIdIn(testPlanIdList);
return testPlanBugMapper.deleteByExample(example); List<BugRelationCase> bugRelationCases = bugRelationCaseMapper.selectByExample(example);
List<String> relateIdsByDirect = bugRelationCases.stream().filter(relatedCase -> StringUtils.isNotEmpty(relatedCase.getCaseId())).map(BugRelationCase::getId).toList();
List<String> relateIdsByPlan = bugRelationCases.stream().filter(relatedCase -> StringUtils.isEmpty(relatedCase.getCaseId())).map(BugRelationCase::getId).toList();
if (CollectionUtils.isNotEmpty(relateIdsByDirect)) {
// 缺陷-用例, 存在直接关联
BugRelationCaseExample updateExample = new BugRelationCaseExample();
updateExample.createCriteria().andIdIn(relateIdsByDirect);
BugRelationCase record = new BugRelationCase();
record.setTestPlanId(StringUtils.EMPTY);
record.setTestPlanCaseId(StringUtils.EMPTY);
bugRelationCaseMapper.updateByExampleSelective(record, updateExample);
}
if (CollectionUtils.isNotEmpty(relateIdsByPlan)) {
// 缺陷-用例, 计划关联
BugRelationCaseExample deleteExample = new BugRelationCaseExample();
deleteExample.createCriteria().andIdIn(relateIdsByPlan);
bugRelationCaseMapper.deleteByExample(deleteExample);
}
return bugRelationCases.size();
} }
@Override @Override
@ -40,4 +83,38 @@ public class TestPlanBugService extends TestPlanResourceService {
} }
/**
* 处理自定义字段
*
* @param bugList 缺陷集合
*/
private void parseCustomField(List<TestPlanBugPageResponse> bugList, String projectId) {
Map<String, String> allHandlerMap = bugCommonService.getAllHandlerMap(projectId);
Map<String, String> allStatusMap = bugCommonService.getAllStatusMap(projectId);
bugList.forEach(bug -> {
// 解析处理人, 状态
bug.setHandleUser(allHandlerMap.get(bug.getHandleUser()));
bug.setStatus(allStatusMap.get(bug.getStatus()));
});
}
/**
* 补充计划-缺陷列表额外信息
* @param bugList 缺陷列表
* @return 缺陷列表全部信息
*/
private List<TestPlanBugPageResponse> buildBugRelatedListExtraInfo(List<TestPlanBugPageResponse> bugList, String planId) {
// 获取用户集合
List<String> userIds = new ArrayList<>(bugList.stream().map(TestPlanBugPageResponse::getCreateUser).distinct().toList());
List<OptionDTO> userOptions = baseUserMapper.selectUserOptionByIds(userIds);
Map<String, String> userMap = userOptions.stream().collect(Collectors.toMap(OptionDTO::getId, OptionDTO::getName));
List<String> bugIds = bugList.stream().map(TestPlanBugPageResponse::getId).toList();
List<TestPlanBugCaseDTO> bugRelatedCases = extTestPlanBugMapper.getBugRelatedCase(bugIds, planId);
Map<String, List<TestPlanBugCaseDTO>> bugRelateCaseMap = bugRelatedCases.stream().collect(Collectors.groupingBy(TestPlanBugCaseDTO::getBugId));
bugList.forEach(bug -> {
bug.setRelateCase(bugRelateCaseMap.get(bug.getId()));
bug.setCreateUser(userMap.get(bug.getCreateUser()));
});
return bugList;
}
} }

View File

@ -19,7 +19,7 @@ import org.springframework.context.annotation.ComponentScan;
MinioProperties.class MinioProperties.class
}) })
@ServletComponentScan @ServletComponentScan
@ComponentScan(basePackages = {"io.metersphere.sdk", "io.metersphere.plan", "io.metersphere.system"}) @ComponentScan(basePackages = {"io.metersphere.sdk", "io.metersphere.plan", "io.metersphere.system", "io.metersphere.project", "io.metersphere.bug"})
public class TestPlanApplication { public class TestPlanApplication {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -0,0 +1,99 @@
package io.metersphere.plan.controller;
import io.metersphere.plan.dto.request.TestPlanBugPageRequest;
import io.metersphere.plan.dto.response.TestPlanBugPageResponse;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MvcResult;
import java.nio.charset.StandardCharsets;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestPlanBugControllerTests extends BaseTest {
@Resource
private ProjectMapper projectMapper;
public static final String TEST_PLAN_BUG_PAGE = "/test-plan/bug/page";
private static final String TEST_PLAN_DELETE = "/test-plan/delete";
@Test
@Order(1)
@Sql(scripts = {"/dml/init_test_plan_bug.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
void testBugPageSuccess() throws Exception {
TestPlanBugPageRequest request = new TestPlanBugPageRequest();
request.setPlanId("test-plan-id-for-bug");
request.setProjectId("100001100001");
request.setCurrent(1);
request.setPageSize(10);
request.setKeyword("oasis");
MvcResult mvcResult = this.requestPostWithOkAndReturn(TEST_PLAN_BUG_PAGE, request);
// 获取返回值
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
// 返回请求正常
Assertions.assertNotNull(resultHolder);
Pager<?> pageData = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
// 返回值不为空
Assertions.assertNotNull(pageData);
// 返回值的页码和当前页码相同
Assertions.assertEquals(pageData.getCurrent(), request.getCurrent());
// 返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= request.getPageSize());
// 返回值中取出第一条数据, 并判断是否包含关键字default
TestPlanBugPageResponse bug = JSON.parseArray(JSON.toJSONString(pageData.getList()), TestPlanBugPageResponse.class).get(0);
Assertions.assertTrue(StringUtils.contains(bug.getTitle(), request.getKeyword())
|| StringUtils.contains(bug.getNum(), request.getKeyword()));
// 数据为空
request.setKeyword("oasis-1");
this.requestPost(TEST_PLAN_BUG_PAGE, request);
}
@Test
@Order(2)
void testBugPageError() throws Exception {
// 参数有误
TestPlanBugPageRequest request = new TestPlanBugPageRequest();
request.setCurrent(1);
request.setPageSize(10);
this.requestPost(TEST_PLAN_BUG_PAGE, request, status().isBadRequest());
// 页码有误
request.setProjectId("100001100001");
request.setPlanId("test-plan-id");
request.setCurrent(0);
request.setPageSize(10);
this.requestPost(TEST_PLAN_BUG_PAGE, request, status().isBadRequest());
// 页数有误
request.setCurrent(1);
request.setPageSize(1);
this.requestPost(TEST_PLAN_BUG_PAGE, request, status().isBadRequest());
}
@Test
@Order(3)
void coverDeletePlan() throws Exception {
Project project = new Project();
project.setId("100001100001");
project.setModuleSetting(JSON.toJSONString(List.of("bugManagement","caseManagement", "apiTest", "testPlan")));
projectMapper.updateByPrimaryKeySelective(project);
this.requestGet(TEST_PLAN_DELETE + "/test-plan-id-for-bug");
this.requestGet(TEST_PLAN_DELETE + "/test-plan-id-for-bug-1");
}
}

View File

@ -0,0 +1,12 @@
INSERT INTO `bug_relation_case`(`id`, `case_id`, `bug_id`, `case_type`, `test_plan_id`, `test_plan_case_id`, `create_user`, `create_time`, `update_time`)
VALUES ('test-plan-bug-tmp-id', 'test-plan-bug-case-id', 'test-plan-bug-id', 'FUNCTIONAL', 'test-plan-id-for-bug', 'test-plan-bug-case-id', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
INSERT INTO `bug_relation_case`(`id`, `case_id`, `bug_id`, `case_type`, `test_plan_id`, `test_plan_case_id`, `create_user`, `create_time`, `update_time`)
VALUES ('test-plan-bug-id-1', 'test-plan-bug-case-id', 'bug-oasis-id-for-plan', 'FUNCTIONAL', 'test-plan-id-for-bug', 'test-plan-bug-case-id', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
INSERT INTO `bug_relation_case`(`id`, `case_id`, `bug_id`, `case_type`, `test_plan_id`, `test_plan_case_id`, `create_user`, `create_time`, `update_time`)
VALUES ('test-plan-bug-id-2', null, 'bug-oasis-id-for-plan', 'FUNCTIONAL', 'test-plan-id-for-bug', 'test-plan-bug-case-id', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP);
INSERT INTO bug (id, num, title, handle_users, handle_user, create_user, create_time,update_user, update_time, delete_user, delete_time, project_id, template_id, platform, status, tags, platform_bug_id, deleted, pos)
VALUES ('bug-oasis-id-for-plan', 100001, 'oasis', 'admin', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, 'admin', UNIX_TIMESTAMP() * 1000, '100001100001', 'bug-template-id', 'Local', 'open', '["default-tag"]', null, 0, 5000);
INSERT INTO `test_plan`(`id`, `num`, `project_id`, `group_id`, `module_id`, `name`, `status`, `type`, `tags`, `create_time`, `create_user`, `update_time`, `update_user`, `planned_start_time`, `planned_end_time`, `actual_start_time`, `actual_end_time`, `description`)
VALUES ('test-plan-id-for-bug', 100001, '100001100001', 'NONE', '1', '测试一下计划-2', 'PREPARED', 'TEST_PLAN', NULL, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, '11');
INSERT INTO `test_plan`(`id`, `num`, `project_id`, `group_id`, `module_id`, `name`, `status`, `type`, `tags`, `create_time`, `create_user`, `update_time`, `update_user`, `planned_start_time`, `planned_end_time`, `actual_start_time`, `actual_end_time`, `description`)
VALUES ('test-plan-id-for-bug-1', 100001, '100001100001', 'NONE', '1', '测试一下计划-3', 'PREPARED', 'TEST_PLAN', NULL, CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, '11');