feat: 脑图保存临时节点

This commit is contained in:
AnAngle 2021-09-14 00:12:37 +08:00 committed by jianxing
parent a61aaf52b6
commit f6ddef4544
15 changed files with 1035 additions and 35 deletions

View File

@ -0,0 +1,19 @@
package io.metersphere.base.domain;
import java.io.Serializable;
import lombok.Data;
@Data
public class MinderExtraNode implements Serializable {
private String id;
private String parentId;
private String groupId;
private String type;
private String nodeData;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,480 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class MinderExtraNodeExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public MinderExtraNodeExample() {
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 andParentIdIsNull() {
addCriterion("parent_id is null");
return (Criteria) this;
}
public Criteria andParentIdIsNotNull() {
addCriterion("parent_id is not null");
return (Criteria) this;
}
public Criteria andParentIdEqualTo(String value) {
addCriterion("parent_id =", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotEqualTo(String value) {
addCriterion("parent_id <>", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdGreaterThan(String value) {
addCriterion("parent_id >", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdGreaterThanOrEqualTo(String value) {
addCriterion("parent_id >=", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdLessThan(String value) {
addCriterion("parent_id <", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdLessThanOrEqualTo(String value) {
addCriterion("parent_id <=", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdLike(String value) {
addCriterion("parent_id like", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotLike(String value) {
addCriterion("parent_id not like", value, "parentId");
return (Criteria) this;
}
public Criteria andParentIdIn(List<String> values) {
addCriterion("parent_id in", values, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotIn(List<String> values) {
addCriterion("parent_id not in", values, "parentId");
return (Criteria) this;
}
public Criteria andParentIdBetween(String value1, String value2) {
addCriterion("parent_id between", value1, value2, "parentId");
return (Criteria) this;
}
public Criteria andParentIdNotBetween(String value1, String value2) {
addCriterion("parent_id not between", value1, value2, "parentId");
return (Criteria) this;
}
public Criteria andGroupIdIsNull() {
addCriterion("group_id is null");
return (Criteria) this;
}
public Criteria andGroupIdIsNotNull() {
addCriterion("group_id is not null");
return (Criteria) this;
}
public Criteria andGroupIdEqualTo(String value) {
addCriterion("group_id =", value, "groupId");
return (Criteria) this;
}
public Criteria andGroupIdNotEqualTo(String value) {
addCriterion("group_id <>", value, "groupId");
return (Criteria) this;
}
public Criteria andGroupIdGreaterThan(String value) {
addCriterion("group_id >", value, "groupId");
return (Criteria) this;
}
public Criteria andGroupIdGreaterThanOrEqualTo(String value) {
addCriterion("group_id >=", value, "groupId");
return (Criteria) this;
}
public Criteria andGroupIdLessThan(String value) {
addCriterion("group_id <", value, "groupId");
return (Criteria) this;
}
public Criteria andGroupIdLessThanOrEqualTo(String value) {
addCriterion("group_id <=", value, "groupId");
return (Criteria) this;
}
public Criteria andGroupIdLike(String value) {
addCriterion("group_id like", value, "groupId");
return (Criteria) this;
}
public Criteria andGroupIdNotLike(String value) {
addCriterion("group_id not like", value, "groupId");
return (Criteria) this;
}
public Criteria andGroupIdIn(List<String> values) {
addCriterion("group_id in", values, "groupId");
return (Criteria) this;
}
public Criteria andGroupIdNotIn(List<String> values) {
addCriterion("group_id not in", values, "groupId");
return (Criteria) this;
}
public Criteria andGroupIdBetween(String value1, String value2) {
addCriterion("group_id between", value1, value2, "groupId");
return (Criteria) this;
}
public Criteria andGroupIdNotBetween(String value1, String value2) {
addCriterion("group_id not between", value1, value2, "groupId");
return (Criteria) this;
}
public Criteria andTypeIsNull() {
addCriterion("`type` is null");
return (Criteria) this;
}
public Criteria andTypeIsNotNull() {
addCriterion("`type` is not null");
return (Criteria) this;
}
public Criteria andTypeEqualTo(String value) {
addCriterion("`type` =", value, "type");
return (Criteria) this;
}
public Criteria andTypeNotEqualTo(String value) {
addCriterion("`type` <>", value, "type");
return (Criteria) this;
}
public Criteria andTypeGreaterThan(String value) {
addCriterion("`type` >", value, "type");
return (Criteria) this;
}
public Criteria andTypeGreaterThanOrEqualTo(String value) {
addCriterion("`type` >=", value, "type");
return (Criteria) this;
}
public Criteria andTypeLessThan(String value) {
addCriterion("`type` <", value, "type");
return (Criteria) this;
}
public Criteria andTypeLessThanOrEqualTo(String value) {
addCriterion("`type` <=", value, "type");
return (Criteria) this;
}
public Criteria andTypeLike(String value) {
addCriterion("`type` like", value, "type");
return (Criteria) this;
}
public Criteria andTypeNotLike(String value) {
addCriterion("`type` not like", value, "type");
return (Criteria) this;
}
public Criteria andTypeIn(List<String> values) {
addCriterion("`type` in", values, "type");
return (Criteria) this;
}
public Criteria andTypeNotIn(List<String> values) {
addCriterion("`type` not in", values, "type");
return (Criteria) this;
}
public Criteria andTypeBetween(String value1, String value2) {
addCriterion("`type` between", value1, value2, "type");
return (Criteria) this;
}
public Criteria andTypeNotBetween(String value1, String value2) {
addCriterion("`type` not between", value1, value2, "type");
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.MinderExtraNode;
import io.metersphere.base.domain.MinderExtraNodeExample;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface MinderExtraNodeMapper {
long countByExample(MinderExtraNodeExample example);
int deleteByExample(MinderExtraNodeExample example);
int deleteByPrimaryKey(String id);
int insert(MinderExtraNode record);
int insertSelective(MinderExtraNode record);
List<MinderExtraNode> selectByExampleWithBLOBs(MinderExtraNodeExample example);
List<MinderExtraNode> selectByExample(MinderExtraNodeExample example);
MinderExtraNode selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") MinderExtraNode record, @Param("example") MinderExtraNodeExample example);
int updateByExampleWithBLOBs(@Param("record") MinderExtraNode record, @Param("example") MinderExtraNodeExample example);
int updateByExample(@Param("record") MinderExtraNode record, @Param("example") MinderExtraNodeExample example);
int updateByPrimaryKeySelective(MinderExtraNode record);
int updateByPrimaryKeyWithBLOBs(MinderExtraNode record);
int updateByPrimaryKey(MinderExtraNode record);
}

View File

@ -0,0 +1,251 @@
<?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.MinderExtraNodeMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.MinderExtraNode">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="parent_id" jdbcType="VARCHAR" property="parentId" />
<result column="group_id" jdbcType="VARCHAR" property="groupId" />
<result column="type" jdbcType="VARCHAR" property="type" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.MinderExtraNode">
<result column="node_data" jdbcType="LONGVARCHAR" property="nodeData" />
</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, parent_id, group_id, `type`
</sql>
<sql id="Blob_Column_List">
node_data
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.MinderExtraNodeExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from minder_extra_node
<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.MinderExtraNodeExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from minder_extra_node
<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 minder_extra_node
where id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
delete from minder_extra_node
where id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.MinderExtraNodeExample">
delete from minder_extra_node
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.MinderExtraNode">
insert into minder_extra_node (id, parent_id, group_id,
`type`, node_data)
values (#{id,jdbcType=VARCHAR}, #{parentId,jdbcType=VARCHAR}, #{groupId,jdbcType=VARCHAR},
#{type,jdbcType=VARCHAR}, #{nodeData,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.MinderExtraNode">
insert into minder_extra_node
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="parentId != null">
parent_id,
</if>
<if test="groupId != null">
group_id,
</if>
<if test="type != null">
`type`,
</if>
<if test="nodeData != null">
node_data,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="parentId != null">
#{parentId,jdbcType=VARCHAR},
</if>
<if test="groupId != null">
#{groupId,jdbcType=VARCHAR},
</if>
<if test="type != null">
#{type,jdbcType=VARCHAR},
</if>
<if test="nodeData != null">
#{nodeData,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.MinderExtraNodeExample" resultType="java.lang.Long">
select count(*) from minder_extra_node
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
update minder_extra_node
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.parentId != null">
parent_id = #{record.parentId,jdbcType=VARCHAR},
</if>
<if test="record.groupId != null">
group_id = #{record.groupId,jdbcType=VARCHAR},
</if>
<if test="record.type != null">
`type` = #{record.type,jdbcType=VARCHAR},
</if>
<if test="record.nodeData != null">
node_data = #{record.nodeData,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update minder_extra_node
set id = #{record.id,jdbcType=VARCHAR},
parent_id = #{record.parentId,jdbcType=VARCHAR},
group_id = #{record.groupId,jdbcType=VARCHAR},
`type` = #{record.type,jdbcType=VARCHAR},
node_data = #{record.nodeData,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update minder_extra_node
set id = #{record.id,jdbcType=VARCHAR},
parent_id = #{record.parentId,jdbcType=VARCHAR},
group_id = #{record.groupId,jdbcType=VARCHAR},
`type` = #{record.type,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.MinderExtraNode">
update minder_extra_node
<set>
<if test="parentId != null">
parent_id = #{parentId,jdbcType=VARCHAR},
</if>
<if test="groupId != null">
group_id = #{groupId,jdbcType=VARCHAR},
</if>
<if test="type != null">
`type` = #{type,jdbcType=VARCHAR},
</if>
<if test="nodeData != null">
node_data = #{nodeData,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.MinderExtraNode">
update minder_extra_node
set parent_id = #{parentId,jdbcType=VARCHAR},
group_id = #{groupId,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR},
node_data = #{nodeData,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.MinderExtraNode">
update minder_extra_node
set parent_id = #{parentId,jdbcType=VARCHAR},
group_id = #{groupId,jdbcType=VARCHAR},
`type` = #{type,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

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

View File

@ -0,0 +1,62 @@
package io.metersphere.service;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.base.domain.MinderExtraNode;
import io.metersphere.base.domain.MinderExtraNodeExample;
import io.metersphere.base.mapper.MinderExtraNodeMapper;
import io.metersphere.track.request.MinderExtraNodeEditRequest;
import org.apache.commons.collections.CollectionUtils;
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;
import java.util.Map;
import java.util.UUID;
@Service
@Transactional(rollbackFor = Exception.class)
public class MinderExtraNodeService {
@Resource
MinderExtraNodeMapper minderExtraNodeMapper;
public void batchEdit(MinderExtraNodeEditRequest request) {
Map<String, List<String>> data = request.getData();
if (data != null) {
data.forEach((parentId, nodes) -> {
nodes.forEach(node -> {
MinderExtraNode minderExtraNode = new MinderExtraNode();
minderExtraNode.setNodeData(node);
minderExtraNode.setParentId(parentId);
JSONObject nodeObj = JSONObject.parseObject(node);
String id = nodeObj.getString("id");
if (StringUtils.isBlank(id) || id.length() < 20) {
minderExtraNode.setId(UUID.randomUUID().toString());
minderExtraNode.setGroupId(request.getGroupId());
minderExtraNode.setType(request.getType());
nodeObj.put("id", minderExtraNode.getId());
minderExtraNode.setNodeData(nodeObj.toJSONString());
minderExtraNodeMapper.insert(minderExtraNode);
} else {
minderExtraNode.setId(id);
minderExtraNodeMapper.updateByPrimaryKeySelective(minderExtraNode);
}
});
});
}
List<String> ids = request.getIds();
if (CollectionUtils.isNotEmpty(ids)) {
MinderExtraNodeExample example = new MinderExtraNodeExample();
example.createCriteria().andIdIn(ids);
minderExtraNodeMapper.deleteByExample(example);
}
}
public List<MinderExtraNode> selectByParentId(String parentId, String groupId) {
MinderExtraNodeExample example = new MinderExtraNodeExample();
example.createCriteria().andParentIdEqualTo(parentId).andGroupIdEqualTo(groupId);
return minderExtraNodeMapper.selectByExampleWithBLOBs(example);
}
}

View File

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

View File

@ -45,7 +45,6 @@ ALTER TABLE test_plan_api_case ADD `order` bigint(20) NOT NULL COMMENT '自定
ALTER TABLE test_plan_api_scenario ADD `order` bigint(20) NOT NULL COMMENT '自定义排序间隔5000'; ALTER TABLE test_plan_api_scenario ADD `order` bigint(20) NOT NULL COMMENT '自定义排序间隔5000';
ALTER TABLE test_plan_load_case ADD `order` bigint(20) NOT NULL COMMENT '自定义排序间隔5000'; ALTER TABLE test_plan_load_case ADD `order` bigint(20) NOT NULL COMMENT '自定义排序间隔5000';
create table if not exists custom_function create table if not exists custom_function
( (
id varchar(50) not null id varchar(50) not null
@ -67,3 +66,13 @@ create table if not exists custom_function
COLLATE utf8mb4_general_ci; COLLATE utf8mb4_general_ci;
CREATE table if not exists `minder_config` (
`id` varchar(50) NOT NULL,
`resource_id` varchar(50) NOT NULL COMMENT '所属的项目或测试计划',
`type` varchar(30) NOT NULL COMMENT '类型,如:用例编辑脑图',
`extra_node` longtext COMMENT '存储脑图节点额外信息',
PRIMARY KEY (`id`)
index(id)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE utf8mb4_general_ci;

View File

@ -1,10 +1,11 @@
<template> <template>
<ms-edit-dialog <ms-edit-dialog
:visible.sync="visible" :visible.sync="visible"
width="30%" width="20%"
:title="$t('请保存')" :title="title"
:with-footer="false" :with-footer="false"
:close-on-click-modal="false"> :close-on-click-modal="false">
{{tip}}
<template v-slot:footer> <template v-slot:footer>
<el-button type="primary" @click="save" @keydown.enter.native.prevent>{{$t('保存')}}</el-button> <el-button type="primary" @click="save" @keydown.enter.native.prevent>{{$t('保存')}}</el-button>
<el-button @click="cancel">{{$t('不保存')}}</el-button> <el-button @click="cancel">{{$t('不保存')}}</el-button>
@ -23,6 +24,7 @@ export default {
data: {} data: {}
} }
}, },
props: ['title','tip'],
methods: { methods: {
open(item) { open(item) {
this.visible = true; this.visible = true;

View File

@ -19,6 +19,8 @@
@save="save" @save="save"
/> />
<is-change-confirm <is-change-confirm
:title="'请保存脑图'"
:tip="'脑图未保存,确认保存脑图吗?'"
@confirm="changeConfirm" @confirm="changeConfirm"
ref="isChangeConfirm"/> ref="isChangeConfirm"/>
</div> </div>
@ -66,7 +68,8 @@ export default {
tagEditCheck: Function, tagEditCheck: Function,
priorityDisableCheck: Function, priorityDisableCheck: Function,
disabled: Boolean, disabled: Boolean,
ignoreNum: Boolean ignoreNum: Boolean,
showModuleTag: Boolean
}, },
data() { data() {
return { return {
@ -77,6 +80,7 @@ export default {
disable: true, disable: true,
id: "root", id: "root",
type: 'node', type: 'node',
resource: this.showModuleTag ? ['模块'] : [],
path: "", path: "",
tagEnable: this.tagEnable tagEnable: this.tagEnable
}, },
@ -148,6 +152,7 @@ export default {
id: item.id, id: item.id,
disable: true, disable: true,
type: 'node', type: 'node',
resource: this.showModuleTag ? ['模块'] : [],
caseNum: item.caseNum, caseNum: item.caseNum,
path: root.data.path + "/" + item.name, path: root.data.path + "/" + item.name,
expandState:"collapse" expandState:"collapse"
@ -203,7 +208,8 @@ export default {
id: nodeData.id, id: nodeData.id,
disable: true, disable: true,
tagEnable: this.tagEnable, tagEnable: this.tagEnable,
type: 'node' type: 'node',
resource: this.showModuleTag ? ['模块'] : [],
}, },
children: [] children: []
}, },

View File

@ -112,6 +112,8 @@
</el-tabs> </el-tabs>
<is-change-confirm <is-change-confirm
:title="'请保存脑图'"
:tip="'脑图未保存,确认保存脑图吗?'"
@confirm="changeConfirm" @confirm="changeConfirm"
ref="isChangeConfirm"/> ref="isChangeConfirm"/>
</ms-main-container> </ms-main-container>

View File

@ -6,6 +6,7 @@
minder-key="testCase" minder-key="testCase"
:select-node="selectNode" :select-node="selectNode"
:distinct-tags="tags" :distinct-tags="tags"
:show-module-tag="true"
:tag-edit-check="tagEditCheck()" :tag-edit-check="tagEditCheck()"
@afterMount="handleAfterMount" @afterMount="handleAfterMount"
:priority-disable-check="priorityDisableCheck()" :priority-disable-check="priorityDisableCheck()"
@ -27,7 +28,7 @@ import {
tagEditCheck, tagEditCheck,
} from "@/business/components/track/common/minder/minderUtils"; } from "@/business/components/track/common/minder/minderUtils";
import {getNodePath, hasPermission} from "@/common/js/utils"; import {getNodePath, hasPermission} from "@/common/js/utils";
import {getTestCasesForMinder} from "@/network/testCase"; import {getTestCasesForMinder, getMinderExtraNode} from "@/network/testCase";
export default { export default {
name: "TestCaseMinder", name: "TestCaseMinder",
components: {MsModuleMinder}, components: {MsModuleMinder},
@ -35,7 +36,7 @@ name: "TestCaseMinder",
return{ return{
testCase: [], testCase: [],
dataMap: new Map(), dataMap: new Map(),
tags: [this.$t('api_test.definition.request.case'), this.$t('test_track.case.prerequisite'), this.$t('commons.remark')], tags: [this.$t('api_test.definition.request.case'), this.$t('test_track.case.prerequisite'), this.$t('commons.remark'), '模块'],
result: {loading: false}, result: {loading: false},
needRefresh: false, needRefresh: false,
} }
@ -63,21 +64,12 @@ name: "TestCaseMinder",
disabled() { disabled() {
return !hasPermission('PROJECT_TRACK_CASE:READ+EDIT'); return !hasPermission('PROJECT_TRACK_CASE:READ+EDIT');
}, },
isChanged() {
return this.$store.state.isTestCaseMinderChanged;
}
}, },
watch: { watch: {
selectNode() { selectNode() {
if (this.$refs.minder) { if (this.$refs.minder) {
this.$refs.minder.handleNodeSelect(this.selectNode); this.$refs.minder.handleNodeSelect(this.selectNode);
} }
},
'$route'(to) {
if (to.name !== 'testCaseCreate' || to.name !== 'testCase' || to.name !== 'testCaseEdit') {
this.$warning('请保存用例');
return false;
}
} }
}, },
mounted() { mounted() {
@ -92,7 +84,8 @@ name: "TestCaseMinder",
methods: { methods: {
handleAfterMount() { handleAfterMount() {
listenNodeSelected(() => { listenNodeSelected(() => {
loadSelectNodes(this.getParam(), getTestCasesForMinder); //
loadSelectNodes(this.getParam(), getTestCasesForMinder, null, getMinderExtraNode);
}); });
listenDblclick(() => { listenDblclick(() => {
@ -137,32 +130,64 @@ name: "TestCaseMinder",
save(data) { save(data) {
let saveCases = []; let saveCases = [];
let deleteCases = []; let deleteCases = [];
this.buildSaveCase(data.root, saveCases, deleteCases, undefined); let saveExtraNode = {};
this.buildSaveCase(data.root, saveCases, deleteCases, saveExtraNode, undefined);
let param = { let param = {
projectId: this.projectId, projectId: this.projectId,
data: saveCases, data: saveCases,
ids: deleteCases.map(item => item.id) ids: deleteCases.map(item => item.id)
} }
let saveCase = new Promise((resolve) => {
this.result = this.$post('/test/case/minder/edit', param, () => { this.result = this.$post('/test/case/minder/edit', param, () => {
resolve();
});
});
let extraNodeParam = {
groupId: this.projectId,
type: "TEST_CASE",
data: saveExtraNode,
ids: deleteCases.map(item => item.id)
}
let saveExtraNodePromise = new Promise((resolve) => {
this.result = this.$post('/minder/extra/node/batch/edit', extraNodeParam, () => {
resolve();
});
});
Promise.all([saveCase, saveExtraNodePromise])
.then(() => {
this.$success(this.$t('commons.save_success')); this.$success(this.$t('commons.save_success'));
handleAfterSave(window.minder.getRoot(), this.getParam()); handleAfterSave(window.minder.getRoot(), this.getParam());
this.setIsChange(false); this.setIsChange(false);
}); });
}, },
buildSaveCase(root, saveCases, deleteCases, parent) { buildSaveCase(root, saveCases, deleteCases, saveExtraNode, parent) {
let data = root.data; let data = root.data;
if (data.resource && data.resource.indexOf(this.$t('api_test.definition.request.case')) > -1) { if (data.resource && data.resource.indexOf(this.$t('api_test.definition.request.case')) > -1) {
this._buildSaveCase(root, saveCases, parent); this._buildSaveCase(root, saveCases, parent);
} else { } else {
let deleteChild = data.deleteChild; let deleteChild = data.deleteChild;
if (deleteChild && deleteChild.length > 0) { if (deleteChild && deleteChild.length > 0
&& data.type === 'node') {
deleteCases.push(...deleteChild); deleteCases.push(...deleteChild);
} }
if (data.type !== 'node' && data.type !== 'tmp') {
let tip = '用例(' + data.text + ')未添加用例标签!'; if (data.type !== 'node' && data.type !== 'tmp'
this.$error(tip) && parent && parent.type === 'node' && data.changed === true) {
throw new Error(tip); //
let nodes = saveExtraNode[parent.id];
if (!nodes) {
nodes = [];
} }
nodes.push(JSON.stringify(this.buildExtraNode(root)));
saveExtraNode[parent.id] = nodes;
}
if (data.id === null) { if (data.id === null) {
let tip = '脑图编辑无法创建模块:' + data.text + ''; let tip = '脑图编辑无法创建模块:' + data.text + '';
this.$error(tip) this.$error(tip)
@ -170,7 +195,7 @@ name: "TestCaseMinder",
} }
if (root.children) { if (root.children) {
root.children.forEach((childNode) => { root.children.forEach((childNode) => {
this.buildSaveCase(childNode, saveCases, deleteCases, root.data); this.buildSaveCase(childNode, saveCases, deleteCases, saveExtraNode, root.data);
}); });
} }
} }
@ -239,6 +264,21 @@ name: "TestCaseMinder",
throw new Error(tip); throw new Error(tip);
} }
}, },
buildExtraNode(node) {
let data = node.data;
let nodeData = {
text: data.text,
id: data.id,
resource: data.resource,
};
if (node.children) {
nodeData.children = [];
node.children.forEach(item => {
nodeData.children.push(this.buildExtraNode(item));
});
}
return nodeData;
},
tagEditCheck() { tagEditCheck() {
return tagEditCheck; return tagEditCheck;
}, },

View File

@ -1,5 +1,7 @@
import i18n from "@/i18n/i18n"; import i18n from "@/i18n/i18n";
import {getTestCasesForMinder} from "@/network/testCase"; import {getTestCasesForMinder} from "@/network/testCase";
import {getMinderExtraNode} from "@/network/testCase";
import {getCurrentProjectID} from "../../../../../common/js/utils";
export function listenNodeSelected(callback) { export function listenNodeSelected(callback) {
let minder = window.minder; let minder = window.minder;
@ -42,7 +44,7 @@ export function listenBeforeExecCommand(callback) {
* @param projectId * @param projectId
* @param result * @param result
*/ */
export function loadNode(node, param, getCaseFuc, setParamCallback) { export function loadNode(node, param, getCaseFuc, setParamCallback, getExtraNodeFuc) {
let data = node.data; let data = node.data;
if (!data.loaded && data.type === 'node') { if (!data.loaded && data.type === 'node') {
if (param.result) { if (param.result) {
@ -56,6 +58,15 @@ export function loadNode(node, param, getCaseFuc, setParamCallback) {
if (getCaseFuc) { if (getCaseFuc) {
getCaseFuc(request, (testCases) => { getCaseFuc(request, (testCases) => {
appendCaseNodes(node, testCases, param, setParamCallback); appendCaseNodes(node, testCases, param, setParamCallback);
if (getExtraNodeFuc) {
param.result.loading = true;
getExtraNodeFuc(getCurrentProjectID(), data.id, (nodes) => {
appendExtraNodes(node, nodes);
param.result.loading = false;
});
}
}); });
} }
} }
@ -67,11 +78,11 @@ export function loadNode(node, param, getCaseFuc, setParamCallback) {
* @param projectId * @param projectId
* @param result * @param result
*/ */
export function loadSelectNodes(param, getCaseFuc, setParamCallback) { export function loadSelectNodes(param, getCaseFuc, setParamCallback, getExtraNodeFuc) {
let minder = window.minder; let minder = window.minder;
let selectNodes = minder.getSelectedNodes(); let selectNodes = minder.getSelectedNodes();
selectNodes.forEach(node => { selectNodes.forEach(node => {
loadNode(node, param, getCaseFuc, setParamCallback); loadNode(node, param, getCaseFuc, setParamCallback, getExtraNodeFuc);
}); });
} }
@ -244,6 +255,29 @@ export function appendCaseNodes(parent, testCases, param, setParamCallback) {
} }
} }
export function appendExtraNodes(parent, nodes) {
if (nodes) {
if (!parent.children) {
parent.children = [];
}
nodes.forEach(i => {
if (i.nodeData) {
let dataObj = JSON.parse(i.nodeData);
_appendExtraNodes(parent, dataObj);
}
});
}
}
function _appendExtraNodes(parent, data) {
let node = appendChildNode(parent, data, true);
if (data.children && data.children.length > 0) {
data.children.forEach(child => {
_appendExtraNodes(node, child);
});
}
}
/** /**
* 去掉已有节点 * 去掉已有节点
* @param parent * @param parent
@ -325,8 +359,12 @@ export function tagEditCheck(resourceName) {
let minder = window.minder; let minder = window.minder;
let selectNodes = minder.getSelectedNodes(); let selectNodes = minder.getSelectedNodes();
if (selectNodes && selectNodes.length > 0) { if (selectNodes && selectNodes.length > 0) {
let resource = selectNodes[0].getParent().data.resource; let lastNodeResource = selectNodes[0].getParent().data.resource;
if (resource && resource.indexOf('用例') > -1 && resourceName === '用例') { if ( resourceName === '模块') {
// 模块不能编辑
return false;
}
if (lastNodeResource && lastNodeResource.indexOf('用例') > -1 && resourceName === '用例') {
return false; return false;
} }
} }
@ -353,7 +391,7 @@ export function handleAfterSave(pNode, param) {
let item = children[i]; let item = children[i];
if (item.data.id === null || (item.data.id && item.data.id.length < 20)) { if (item.data.id === null || (item.data.id && item.data.id.length < 20)) {
pNode.data.loaded = false; pNode.data.loaded = false;
loadNode(pNode, param, getTestCasesForMinder); loadNode(pNode, param, getTestCasesForMinder, null, getMinderExtraNode);
return; return;
} }
if (item.data.changed) { if (item.data.changed) {

View File

@ -2,6 +2,7 @@ import {post, get} from "@/common/js/ajax";
import {success} from "@/common/js/message"; import {success} from "@/common/js/message";
import i18n from "@/i18n/i18n"; import i18n from "@/i18n/i18n";
import {basePost} from "@/network/base-network"; import {basePost} from "@/network/base-network";
import {baseGet} from "./base-network";
export function getTestCasesForMinder(request, callback) { export function getTestCasesForMinder(request, callback) {
return post('/test/case/list/minder', request, (response) => { return post('/test/case/list/minder', request, (response) => {
@ -53,3 +54,8 @@ export function deleteRelateTest(caseId, testId, callback) {
export function editTestCaseOrder(request, callback) { export function editTestCaseOrder(request, callback) {
return basePost('/test/case/edit/order', request, callback); return basePost('/test/case/edit/order', request, callback);
} }
export function getMinderExtraNode(groupId, nodeId, callback) {
return baseGet('/minder/extra/node/list/' + groupId + '/' + nodeId, callback);
}

0
git Normal file
View File