feat: 缺陷详情增加评论并且增加站内信通知 (#8703)

* feat: 缺陷详情增加评论并且增加站内信通知
--story=1004214 --user=张大海 11.缺陷详情添加评论 以免修改状态无法增加描述 https://www.tapd.cn/55049933/s/1084637

* refactor: 代码优化

Co-authored-by: zhangdahai111 <dahai.zhang@fit2cloud.com>
Co-authored-by: jianxing <41557596+AgAngle@users.noreply.github.com>
This commit is contained in:
metersphere-bot 2021-12-22 10:22:34 +08:00 committed by GitHub
parent 7115516bf0
commit 0e4cc6bb42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1389 additions and 11 deletions

View File

@ -0,0 +1,23 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class IssueComment implements Serializable {
private String id;
private String issueId;
private String author;
private Long createTime;
private Long updateTime;
private String status;
private String description;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,600 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class IssueCommentExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public IssueCommentExample() {
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 andIssueIdIsNull() {
addCriterion("issue_id is null");
return (Criteria) this;
}
public Criteria andIssueIdIsNotNull() {
addCriterion("issue_id is not null");
return (Criteria) this;
}
public Criteria andIssueIdEqualTo(String value) {
addCriterion("issue_id =", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdNotEqualTo(String value) {
addCriterion("issue_id <>", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdGreaterThan(String value) {
addCriterion("issue_id >", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdGreaterThanOrEqualTo(String value) {
addCriterion("issue_id >=", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdLessThan(String value) {
addCriterion("issue_id <", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdLessThanOrEqualTo(String value) {
addCriterion("issue_id <=", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdLike(String value) {
addCriterion("issue_id like", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdNotLike(String value) {
addCriterion("issue_id not like", value, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdIn(List<String> values) {
addCriterion("issue_id in", values, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdNotIn(List<String> values) {
addCriterion("issue_id not in", values, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdBetween(String value1, String value2) {
addCriterion("issue_id between", value1, value2, "issueId");
return (Criteria) this;
}
public Criteria andIssueIdNotBetween(String value1, String value2) {
addCriterion("issue_id not between", value1, value2, "issueId");
return (Criteria) this;
}
public Criteria andAuthorIsNull() {
addCriterion("author is null");
return (Criteria) this;
}
public Criteria andAuthorIsNotNull() {
addCriterion("author is not null");
return (Criteria) this;
}
public Criteria andAuthorEqualTo(String value) {
addCriterion("author =", value, "author");
return (Criteria) this;
}
public Criteria andAuthorNotEqualTo(String value) {
addCriterion("author <>", value, "author");
return (Criteria) this;
}
public Criteria andAuthorGreaterThan(String value) {
addCriterion("author >", value, "author");
return (Criteria) this;
}
public Criteria andAuthorGreaterThanOrEqualTo(String value) {
addCriterion("author >=", value, "author");
return (Criteria) this;
}
public Criteria andAuthorLessThan(String value) {
addCriterion("author <", value, "author");
return (Criteria) this;
}
public Criteria andAuthorLessThanOrEqualTo(String value) {
addCriterion("author <=", value, "author");
return (Criteria) this;
}
public Criteria andAuthorLike(String value) {
addCriterion("author like", value, "author");
return (Criteria) this;
}
public Criteria andAuthorNotLike(String value) {
addCriterion("author not like", value, "author");
return (Criteria) this;
}
public Criteria andAuthorIn(List<String> values) {
addCriterion("author in", values, "author");
return (Criteria) this;
}
public Criteria andAuthorNotIn(List<String> values) {
addCriterion("author not in", values, "author");
return (Criteria) this;
}
public Criteria andAuthorBetween(String value1, String value2) {
addCriterion("author between", value1, value2, "author");
return (Criteria) this;
}
public Criteria andAuthorNotBetween(String value1, String value2) {
addCriterion("author not between", value1, value2, "author");
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 andUpdateTimeIsNull() {
addCriterion("update_time is null");
return (Criteria) this;
}
public Criteria andUpdateTimeIsNotNull() {
addCriterion("update_time is not null");
return (Criteria) this;
}
public Criteria andUpdateTimeEqualTo(Long value) {
addCriterion("update_time =", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotEqualTo(Long value) {
addCriterion("update_time <>", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThan(Long value) {
addCriterion("update_time >", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("update_time >=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThan(Long value) {
addCriterion("update_time <", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeLessThanOrEqualTo(Long value) {
addCriterion("update_time <=", value, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeIn(List<Long> values) {
addCriterion("update_time in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotIn(List<Long> values) {
addCriterion("update_time not in", values, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeBetween(Long value1, Long value2) {
addCriterion("update_time between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andUpdateTimeNotBetween(Long value1, Long value2) {
addCriterion("update_time not between", value1, value2, "updateTime");
return (Criteria) this;
}
public Criteria andStatusIsNull() {
addCriterion("`status` is null");
return (Criteria) this;
}
public Criteria andStatusIsNotNull() {
addCriterion("`status` is not null");
return (Criteria) this;
}
public Criteria andStatusEqualTo(String value) {
addCriterion("`status` =", value, "status");
return (Criteria) this;
}
public Criteria andStatusNotEqualTo(String value) {
addCriterion("`status` <>", value, "status");
return (Criteria) this;
}
public Criteria andStatusGreaterThan(String value) {
addCriterion("`status` >", value, "status");
return (Criteria) this;
}
public Criteria andStatusGreaterThanOrEqualTo(String value) {
addCriterion("`status` >=", value, "status");
return (Criteria) this;
}
public Criteria andStatusLessThan(String value) {
addCriterion("`status` <", value, "status");
return (Criteria) this;
}
public Criteria andStatusLessThanOrEqualTo(String value) {
addCriterion("`status` <=", value, "status");
return (Criteria) this;
}
public Criteria andStatusLike(String value) {
addCriterion("`status` like", value, "status");
return (Criteria) this;
}
public Criteria andStatusNotLike(String value) {
addCriterion("`status` not like", value, "status");
return (Criteria) this;
}
public Criteria andStatusIn(List<String> values) {
addCriterion("`status` in", values, "status");
return (Criteria) this;
}
public Criteria andStatusNotIn(List<String> values) {
addCriterion("`status` not in", values, "status");
return (Criteria) this;
}
public Criteria andStatusBetween(String value1, String value2) {
addCriterion("`status` between", value1, value2, "status");
return (Criteria) this;
}
public Criteria andStatusNotBetween(String value1, String value2) {
addCriterion("`status` not between", value1, value2, "status");
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

@ -0,0 +1,36 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.IssueComment;
import io.metersphere.base.domain.IssueCommentExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface IssueCommentMapper {
long countByExample(IssueCommentExample example);
int deleteByExample(IssueCommentExample example);
int deleteByPrimaryKey(String id);
int insert(IssueComment record);
int insertSelective(IssueComment record);
List<IssueComment> selectByExampleWithBLOBs(IssueCommentExample example);
List<IssueComment> selectByExample(IssueCommentExample example);
IssueComment selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") IssueComment record, @Param("example") IssueCommentExample example);
int updateByExampleWithBLOBs(@Param("record") IssueComment record, @Param("example") IssueCommentExample example);
int updateByExample(@Param("record") IssueComment record, @Param("example") IssueCommentExample example);
int updateByPrimaryKeySelective(IssueComment record);
int updateByPrimaryKeyWithBLOBs(IssueComment record);
int updateByPrimaryKey(IssueComment record);
}

View File

@ -0,0 +1,287 @@
<?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.base.mapper.IssueCommentMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.IssueComment">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="issue_id" jdbcType="VARCHAR" property="issueId" />
<result column="author" jdbcType="VARCHAR" property="author" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="status" jdbcType="VARCHAR" property="status" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.IssueComment">
<result column="description" jdbcType="LONGVARCHAR" property="description" />
</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, issue_id, author, create_time, update_time, `status`
</sql>
<sql id="Blob_Column_List">
description
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.IssueCommentExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from issue_comment
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.base.domain.IssueCommentExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from issue_comment
<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="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from issue_comment
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from issue_comment
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.IssueCommentExample">
delete from issue_comment
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.IssueComment">
insert into issue_comment (id, issue_id, author,
create_time, update_time, `status`,
description)
values (#{id,jdbcType=VARCHAR}, #{issueId,jdbcType=VARCHAR}, #{author,jdbcType=VARCHAR},
#{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT}, #{status,jdbcType=VARCHAR},
#{description,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.IssueComment">
insert into issue_comment
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="issueId != null">
issue_id,
</if>
<if test="author != null">
author,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="status != null">
`status`,
</if>
<if test="description != null">
description,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="issueId != null">
#{issueId,jdbcType=VARCHAR},
</if>
<if test="author != null">
#{author,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=BIGINT},
</if>
<if test="status != null">
#{status,jdbcType=VARCHAR},
</if>
<if test="description != null">
#{description,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.IssueCommentExample" resultType="java.lang.Long">
select count(*) from issue_comment
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update issue_comment
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.issueId != null">
issue_id = #{record.issueId,jdbcType=VARCHAR},
</if>
<if test="record.author != null">
author = #{record.author,jdbcType=VARCHAR},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
update_time = #{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.status != null">
`status` = #{record.status,jdbcType=VARCHAR},
</if>
<if test="record.description != null">
description = #{record.description,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update issue_comment
set id = #{record.id,jdbcType=VARCHAR},
issue_id = #{record.issueId,jdbcType=VARCHAR},
author = #{record.author,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
`status` = #{record.status,jdbcType=VARCHAR},
description = #{record.description,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update issue_comment
set id = #{record.id,jdbcType=VARCHAR},
issue_id = #{record.issueId,jdbcType=VARCHAR},
author = #{record.author,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
`status` = #{record.status,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.IssueComment">
update issue_comment
<set>
<if test="issueId != null">
issue_id = #{issueId,jdbcType=VARCHAR},
</if>
<if test="author != null">
author = #{author,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=BIGINT},
</if>
<if test="status != null">
`status` = #{status,jdbcType=VARCHAR},
</if>
<if test="description != null">
description = #{description,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.IssueComment">
update issue_comment
set issue_id = #{issueId,jdbcType=VARCHAR},
author = #{author,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
`status` = #{status,jdbcType=VARCHAR},
description = #{description,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.IssueComment">
update issue_comment
set issue_id = #{issueId,jdbcType=VARCHAR},
author = #{author,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
`status` = #{status,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -0,0 +1,18 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.track.dto.IssueCommentDTO;
import io.metersphere.track.dto.TestCaseCommentDTO;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface ExtIssueCommentMapper {
/**
* 获取用例的评论
* @param issueId
* @return
*/
List<IssueCommentDTO> getComments(@Param("issueId") String issueId);
}

View File

@ -0,0 +1,15 @@
<?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.base.mapper.ext.ExtIssueCommentMapper">
<select id="getComments" resultType="io.metersphere.track.dto.IssueCommentDTO"
parameterType="java.lang.String">
select *, user.name as authorName
from issue_comment,
user
where issue_comment.author = user.id
and issue_id = #{issueId}
order by issue_comment.update_time desc
</select>
</mapper>

View File

@ -0,0 +1,56 @@
package io.metersphere.track.controller;
import io.metersphere.base.domain.IssueComment;
import io.metersphere.commons.constants.NoticeConstants;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.PermissionConstants;
import io.metersphere.log.annotation.MsAuditLog;
import io.metersphere.notice.annotation.SendNotice;
import io.metersphere.track.dto.IssueCommentDTO;
import io.metersphere.track.request.issues.IssuesRelevanceRequest;
import io.metersphere.track.request.issues.SaveIssueCommentRequest;
import io.metersphere.track.service.IssueCommentService;
import io.metersphere.track.service.IssuesService;
import io.metersphere.track.service.TestCaseCommentService;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
@RequestMapping("/issues/comment")
@RestController
public class IssueCommentController {
@Resource
private IssueCommentService issueCommentService;
@PostMapping("/save")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_COMMENT)
@SendNotice(taskType = NoticeConstants.TaskType.DEFECT_TASK, target = "#targetClass.get(#request.issuesId)", targetClass = IssuesService.class,
event = NoticeConstants.Event.COMMENT, mailTemplate = "track/IssuesCommentUpdate", subject = "缺陷评论更新通知")
public IssueComment saveComment(@RequestBody IssuesRelevanceRequest request) {
request.setId(UUID.randomUUID().toString());
return issueCommentService.saveComment(request);
}
@GetMapping("/list/{issueId}")
public List<IssueCommentDTO> getComments(@PathVariable String issueId) {
return issueCommentService.getComments(issueId);
}
@GetMapping("/delete/{commentId}")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_COMMENT)
@MsAuditLog(module = "track_bug", type = OperLogConstants.DELETE, beforeEvent = "#msClass.getLogDetails(#commentId)", msClass = TestCaseCommentService.class)
public void deleteComment(@PathVariable String commentId) {
issueCommentService.delete(commentId);
}
@PostMapping("/edit")
@RequiresPermissions(PermissionConstants.PROJECT_TRACK_REVIEW_READ_COMMENT)
@MsAuditLog(module = "track_bug", type = OperLogConstants.UPDATE, beforeEvent = "#msClass.getLogDetails(#request.id)", content = "#msClass.getLogDetails(#request.id)", msClass = TestCaseCommentService.class)
public IssueComment editComment(@RequestBody SaveIssueCommentRequest request) {
return issueCommentService.edit(request);
}
}

View File

@ -150,4 +150,5 @@ public class IssuesController {
public IssueTemplateDao getThirdPartTemplate(@PathVariable String projectId) {
return issuesService.getThirdPartTemplate(projectId);
}
}

View File

@ -0,0 +1,9 @@
package io.metersphere.track.dto;
import io.metersphere.base.domain.IssueComment;
import lombok.Data;
@Data
public class IssueCommentDTO extends IssueComment {
private String authorName;
}

View File

@ -10,6 +10,8 @@ import java.util.List;
@Getter
@Setter
public class IssuesRelevanceRequest {
private String id;
/**
* 缺陷ID
*/
@ -30,4 +32,6 @@ public class IssuesRelevanceRequest {
private List<String> issueIds;
private Boolean checked;
private String description;
}

View File

@ -0,0 +1,11 @@
package io.metersphere.track.request.issues;
import io.metersphere.base.domain.IssueComment;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SaveIssueCommentRequest extends IssueComment {
private String reviewId;
}

View File

@ -0,0 +1,80 @@
package io.metersphere.track.service;
import com.alibaba.fastjson.JSON;
import io.metersphere.base.domain.IssueComment;
import io.metersphere.base.domain.Issues;
import io.metersphere.base.mapper.IssueCommentMapper;
import io.metersphere.base.mapper.IssuesMapper;
import io.metersphere.base.mapper.ext.ExtIssueCommentMapper;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails;
import io.metersphere.log.vo.track.TestCaseReviewReference;
import io.metersphere.track.dto.IssueCommentDTO;
import io.metersphere.track.request.issues.IssuesRelevanceRequest;
import io.metersphere.track.request.issues.SaveIssueCommentRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
@Service
@Transactional(rollbackFor = Exception.class)
public class IssueCommentService {
@Resource
private IssuesMapper issuesMapper;
@Resource
private ExtIssueCommentMapper extIssueCommentMapper;
@Resource
private IssueCommentMapper issueCommentMapper;
public IssueComment saveComment(IssuesRelevanceRequest request) {
IssueComment issueComment = new IssueComment();
issueComment.setId(request.getId());
issueComment.setAuthor(SessionUtils.getUser().getId());
issueComment.setIssueId(request.getIssuesId());
issueComment.setCreateTime(System.currentTimeMillis());
issueComment.setUpdateTime(System.currentTimeMillis());
issueComment.setDescription(request.getDescription());
issueCommentMapper.insert(issueComment);
return issueComment;
}
public List<IssueCommentDTO> getComments(String caseId) {
return extIssueCommentMapper.getComments(caseId);
}
public void delete(String commentId) {
checkCommentOwner(commentId);
issueCommentMapper.deleteByPrimaryKey(commentId);
}
public IssueComment edit(SaveIssueCommentRequest request) {
checkCommentOwner(request.getId());
issueCommentMapper.updateByPrimaryKeySelective(request);
return issueCommentMapper.selectByPrimaryKey(request.getId());
}
private void checkCommentOwner(String commentId) {
IssueComment comment = issueCommentMapper.selectByPrimaryKey(commentId);
if (!StringUtils.equals(comment.getAuthor(), SessionUtils.getUser().getId())) {
MSException.throwException(Translator.get("check_owner_comment"));
}
}
public String getLogDetails(String id) {
IssueComment issueComment = issueCommentMapper.selectByPrimaryKey(id);
if (issueComment != null) {
Issues review = issuesMapper.selectByPrimaryKey(issueComment.getIssueId());
List<DetailColumn> columns = ReflexObjectUtil.getColumns(issueComment, TestCaseReviewReference.commentReviewColumns);
OperatingLogDetails details = new OperatingLogDetails(JSON.toJSONString(issueComment.getId()), review.getProjectId(), issueComment.getDescription(), issueComment.getAuthor(), columns);
return JSON.toJSONString(details);
}
return null;
}
}

View File

@ -64,8 +64,6 @@ public class IssuesService {
@Resource
private TestCaseIssuesMapper testCaseIssuesMapper;
@Resource
private IssueTemplateMapper issueTemplateMapper;
@Resource
private ExtIssuesMapper extIssuesMapper;
@Resource
private CustomFieldTemplateService customFieldTemplateService;
@ -111,6 +109,7 @@ public class IssuesService {
//saveFollows(issuesRequest.getId(), issuesRequest.getFollows());
// todo 缺陷更新事件
}
public void saveFollows(String issueId, List<String> follows) {
IssueFollowExample example = new IssueFollowExample();
example.createCriteria().andIssueIdEqualTo(issueId);
@ -124,6 +123,7 @@ public class IssuesService {
}
}
}
public List<AbstractIssuePlatform> getAddPlatforms(IssuesUpdateRequest updateRequest) {
List<String> platforms = new ArrayList<>();
if (StringUtils.isNotBlank(updateRequest.getTestCaseId())) {
@ -353,7 +353,7 @@ public class IssuesService {
.collect(Collectors.toList());
item.setCaseIds(caseIds);
item.setCaseCount(testCaseIssues.size());
if(StringUtils.equals(item.getPlatform(),"Tapd")){
if (StringUtils.equals(item.getPlatform(), "Tapd")) {
TapdPlatform platform = (TapdPlatform) IssueFactory.createPlatform(item.getPlatform(), request);
List<String> tapdUsers = platform.getTapdUsers(item.getProjectId(), item.getPlatformId());
item.setTapdUsers(tapdUsers);
@ -469,6 +469,7 @@ public class IssuesService {
/**
* 获取默认的自定义字段的取值同步之后更新成第三方平台的值
*
* @param projectId
* @return
*/
@ -606,7 +607,7 @@ public class IssuesService {
issuesMapper.updateByPrimaryKeySelective(issues);
}
public List<IssuesDao> getCountByStatus(IssuesRequest request){
public List<IssuesDao> getCountByStatus(IssuesRequest request) {
return extIssuesMapper.getCountByStatus(request);
}
@ -619,7 +620,7 @@ public class IssuesService {
IssueFollowExample example = new IssueFollowExample();
example.createCriteria().andIssueIdEqualTo(issueId);
List<IssueFollow> follows = issueFollowMapper.selectByExample(example);
if(follows==null||follows.size()==0){
if (follows == null || follows.size() == 0) {
return result;
}
result = follows.stream().map(IssueFollow::getFollowId).distinct().collect(Collectors.toList());
@ -635,6 +636,7 @@ public class IssuesService {
return issuesMapper.selectByExampleWithBLOBs(example);
}
public IssueTemplateDao getThirdPartTemplate(String projectId) {
if (StringUtils.isNotBlank(projectId)) {
Project project = projectService.getProjectById(projectId);

View File

@ -65,6 +65,19 @@ CREATE TABLE IF NOT EXISTS `api_scenario_report_structure`
INSERT INTO user_group_permission (id, group_id, permission_id, module_id)
VALUES (UUID(), 'project_app_manager', 'PROJECT_APP_MANAGER:READ+EDIT', 'PROJECT_APP_MANAGER');
CREATE TABLE `issue_comment`
(
`id` varchar(64) NOT NULL,
`issue_id` varchar(64) DEFAULT NULL,
`description` text,
`author` varchar(50) DEFAULT NULL,
`create_time` bigint(13) DEFAULT NULL,
`update_time` bigint(13) DEFAULT NULL,
`status` varchar(80) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
CREATE TABLE IF NOT EXISTS `api_execution_queue`
(
`id` varchar(50) NOT NULL COMMENT 'ID',
@ -90,4 +103,5 @@ CREATE TABLE IF NOT EXISTS `api_execution_queue_detail`
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci;
ALTER TABLE load_test
MODIFY name VARCHAR(255) NOT NULL COMMENT 'Test name';
MODIFY name VARCHAR(255) NOT NULL COMMENT 'Test name';

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MeterSphere</title>
</head>
<body>
<div>
<p>${operator}更新了缺陷评论: ${title}</p>
</div>
</body>
</html>

View File

@ -174,6 +174,7 @@ export default {
{value: 'CREATE', label: this.$t('commons.create')},
{value: 'UPDATE', label: this.$t('commons.update')},
{value: 'DELETE', label: this.$t('commons.delete')},
{value: 'COMMENT', label: this.$t('commons.comment')},
],
variables: [
{
@ -378,6 +379,14 @@ export default {
}
}
break;
case "COMMENT":
testPlanReceivers.unshift({id: 'CREATOR', name: this.$t('commons.create_user')});
if (row.isSet) {
if (i2 < 0) {
row.userIds.unshift('CREATOR');
}
}
break;
default:
break;
}

View File

@ -411,6 +411,7 @@ export default {
}
},
methods: {
alert:alert,
currentUser: () => {
return getCurrentUser();
},

View File

@ -0,0 +1,118 @@
<template>
<el-dialog :visible.sync="dialogTableVisible" append-to-body>
<div v-loading="result.loading">
<div class="editors_div_style">
<div id="editorsDiv">
<ms-mark-down-text prop="description" :data="from" :toolbars="toolbars"/>
</div>
</div>
<div>
<el-button type="primary" size="mini" class="send-btn" @click="sendComment" :disabled="isReadOnly">
{{ $t('test_track.comment.send') }}
</el-button>
</div>
</div>
</el-dialog>
</template>
<script>
import ReviewCommentItem from "@/business/components/track/review/commom/ReviewCommentItem";
import {uploadMarkDownImg} from "@/network/image";
import MsMarkDownText from "@/business/components/track/case/components/MsMarkDownText";
export default {
name: "IssueComment",
components: {MsMarkDownText, ReviewCommentItem},
props: {
issuesId: String,
reviewId: String,
},
data() {
return {
result: {},
from: {
description: ''
},
isReadOnly: false,
dialogTableVisible: false,
toolbars: {
bold: false, //
italic: false, //
header: false, //
underline: false, // 线
strikethrough: false, // 线
mark: false, //
superscript: false, //
subscript: false, //
quote: false, //
ol: false, //
ul: false, //
link: false, //
imagelink: true, //
code: false, // code
table: false, //
fullscreen: false, //
readmodel: false, //
htmlcode: false, // html
help: false, //
/* 1.3.5 */
undo: false, //
redo: false, //
trash: false, //
save: false, // eventssave
/* 1.4.2 */
navigation: false, //
/* 2.1.8 */
alignleft: false, //
aligncenter: false, //
alignright: false, //
/* 2.2.1 */
subfield: false, //
preview: false, //
}
};
},
methods: {
open() {
this.dialogTableVisible = true;
},
sendComment() {
let comment = {};
comment.issuesId = this.issuesId;
comment.description = this.from.description;
if (!comment.description) {
this.$warning(this.$t('test_track.comment.description_is_null'));
return;
}
this.result = this.$post('/issues/comment/save', comment, () => {
this.$success(this.$t('test_track.comment.send_success'));
this.refresh(comment.IssueId);
this.from.description = '';
this.dialogTableVisible = false;
});
},
refresh(id) {
this.$emit('getComments');
}
}
};
</script>
<style scoped>
.send-btn {
margin-top: 5px;
width: 100%;
}
.comment-list {
overflow-y: scroll;
height: calc(100vh - 250px);
}
.editors_div_style {
height: 300px;
overflow: auto
}
</style>

View File

@ -66,6 +66,31 @@
ref="testCaseIssueList"/>
</el-form-item>
<!-- <form-rich-text-item :title="$t('commons.remark')" :data="form" prop="remark"/>-->
<el-row style="margin-top: 10px" v-if="type!=='add'">
<el-col :span="20" :offset="1">{{ $t('test_track.review.comment') }}:
<el-button icon="el-icon-plus" type="mini" @click="openComment"></el-button>
</el-col>
</el-row>
<el-row>
<el-col :span="20" :offset="1">
<review-comment-item v-for="(comment,index) in comments"
:key="index"
:comment="comment"
@refresh="getComments" api-url="/issues"/>
<div v-if="comments.length === 0" style="text-align: center">
<i class="el-icon-chat-line-square" style="font-size: 15px;color: #8a8b8d;">
<span style="font-size: 15px; color: #8a8b8d;">
{{ $t('test_track.comment.no_comment') }}
</span>
</i>
</div>
</el-col>
</el-row>
<issue-comment :issues-id="form.id"
@getComments="getComments" ref="issueComment"/>
</el-form>
</el-scrollbar>
@ -92,6 +117,9 @@ import {
} from "@/common/js/utils";
import {enableThirdPartTemplate, getIssuePartTemplateWithProject} from "@/network/Issue";
import CustomFiledFormItem from "@/business/components/common/components/form/CustomFiledFormItem";
import MsMarkDownText from "@/business/components/track/case/components/MsMarkDownText";
import IssueComment from "@/business/components/track/issue/IssueComment";
import ReviewCommentItem from "@/business/components/track/review/commom/ReviewCommentItem";
export default {
name: "IssueEditDetail",
@ -104,10 +132,14 @@ export default {
CustomFieldRelateList,
CustomFieldFormList,
MsFormDivider,
TemplateComponentEditHeader
TemplateComponentEditHeader,
MsMarkDownText,
IssueComment,
ReviewCommentItem
},
data() {
return {
type: null,
issueId:'',
result: {
loading: false
@ -133,13 +165,50 @@ export default {
title: '',
description: '',
creator: null,
remark: null
},
tapdUsers: [],
zentaoUsers: [],
Builds: [],
hasTapdId: false,
hasZentaoId: false,
currentProject: null
currentProject: null,
toolbars: {
bold: false, //
italic: false, //
header: false, //
underline: false, // 线
strikethrough: false, // 线
mark: false, //
superscript: false, //
subscript: false, //
quote: false, //
ol: false, //
ul: false, //
link: false, //
imagelink: true, //
code: false, // code
table: false, //
fullscreen: false, //
readmodel: false, //
htmlcode: false, // html
help: false, //
/* 1.3.5 */
undo: false, //
redo: false, //
trash: false, //
save: false, // eventssave
/* 1.4.2 */
navigation: false, //
/* 2.1.8 */
alignleft: false, //
aligncenter: false, //
alignright: false, //
/* 2.2.1 */
subfield: false, //
preview: false, //
},
comments: []
};
},
props: {
@ -259,6 +328,7 @@ export default {
if (this.$refs.testCaseIssueList) {
this.$refs.testCaseIssueList.initTableData();
}
this.getComments();
});
},
save() {
@ -349,6 +419,16 @@ export default {
});
}
}
},
openComment() {
this.$refs.issueComment.open();
},
getComments() {
if (this.issueId) {
this.result = this.$get('/issues/comment/list/' + this.issueId, res => {
this.comments = res.data;
})
}
}
}
};

View File

@ -1,6 +1,7 @@
<template>
<ms-container>
<ms-main-container>
<el-card class="table-card">
<template v-slot:header>
<ms-table-header :create-permission="['PROJECT_TRACK_ISSUE:READ+CREATE']" :condition.sync="page.condition" @search="getIssues" @create="handleCreate"

View File

@ -5,7 +5,7 @@
ref="reviewComments"
:comment="comment"
@refresh="refresh"
:review-status="reviewStatus"/>
:review-status="reviewStatus" api-url="/test/case"/>
<div v-if="comments.length === 0" style="text-align: center" >
<i class="el-icon-chat-line-square" style="font-size: 15px;color: #8a8b8d;">
<span style="font-size: 15px; color: #8a8b8d;">

View File

@ -77,6 +77,7 @@ export default {
default: false
},
reviewStatus: String,
apiUrl: String
},
data() {
return {
@ -106,7 +107,7 @@ export default {
this.$get('/resource/md/delete/' + imgName);
});
}
this.$get("/test/case/comment/delete/" + this.comment.id, () => {
this.$get(this.apiUrl + "/comment/delete/" + this.comment.id, () => {
this.$success(this.$t('commons.delete_success'));
this.$emit("refresh");
});
@ -120,7 +121,7 @@ export default {
this.visible = true;
},
editComment() {
this.$post("/test/case/comment/edit", {id: this.comment.id, description: this.description}, () => {
this.$post(this.apiUrl + "/comment/edit", {id: this.comment.id, description: this.description}, () => {
this.visible = false;
this.$success(this.$t('commons.modify_success'));
this.$emit("refresh");