feat(接口测试): 接口定义、场景自动化的回收站左侧展示模块树

--task=1008553
--user=宋天阳
【接口测试】----场景自动化、接口定义
https://www.tapd.cn/55049933/s/1220573
This commit is contained in:
song-tianyang 2022-08-04 10:41:33 +08:00 committed by 建国
parent c6e7008e1b
commit 0ff936b802
24 changed files with 611 additions and 296 deletions

View File

@ -39,6 +39,17 @@ public class ApiModuleController {
return apiModuleService.getNodeTreeByProjectId(projectId, protocol, versionId);
}
@GetMapping("/trash/list/{projectId}/{protocol}/{versionId}")
public List<ApiModuleDTO> getTrashNodeByProtocolAndProjectId(@PathVariable String projectId, @PathVariable String protocol,
@PathVariable String versionId) {
return apiModuleService.getTrashNodeTreeByProtocolAndProjectId(projectId, protocol, versionId);
}
@GetMapping("/trash/list/{projectId}/{protocol}")
public List<ApiModuleDTO> getTrashNodeByProtocolAndProjectId(@PathVariable String projectId, @PathVariable String protocol) {
return apiModuleService.getTrashNodeTreeByProtocolAndProjectId(projectId, protocol, null);
}
@GetMapping("/trashCount/{projectId}/{protocol}")
public long trashCount(@PathVariable String projectId, @PathVariable String protocol) {
String userId = SessionUtils.getUserId();

View File

@ -28,6 +28,12 @@ public class ApiScenarioModuleController {
return apiScenarioModuleService.getNodeTreeByProjectId(projectId);
}
@GetMapping("/trash/list/{projectId}")
public List<ApiScenarioModuleDTO> getTrashNodeByProjectId(@PathVariable String projectId) {
checkPermissionService.checkProjectOwner(projectId);
return apiScenarioModuleService.getTrashNodeTreeByProjectId(projectId);
}
@PostMapping("/add")
@MsAuditLog(module = OperLogModule.API_AUTOMATION, type = OperLogConstants.CREATE, title = "#node.name", content = "#msClass.getLogDetails(#node)", msClass = ApiScenarioModuleService.class)
public String addNode(@RequestBody ApiScenarioModule node) {

View File

@ -2338,4 +2338,13 @@ public class ApiAutomationService {
return !StringUtils.equals(existApiScenario.getScenarioDefinition(), apiScenario.getScenarioDefinition());
}
public void updateNoModuleToDefaultModule(String projectId, String status, String id) {
this.extApiScenarioMapper.updateNoModuleToDefaultModule(projectId, status, id);
}
public Map<String, List<ApiScenario>> selectApiBaseInfoGroupByModuleId(String projectId, String status) {
List<ApiScenario> apiScenarioList = extApiScenarioMapper.selectBaseInfoByProjectIdAndStatus(projectId, status);
return apiScenarioList.stream().collect(Collectors.groupingBy(ApiScenario::getApiScenarioModuleId));
}
}

View File

@ -2656,4 +2656,24 @@ public class ApiDefinitionService {
apiDefinitionFollowMapper.deleteByExample(example);
}
}
public Map<String, List<ApiDefinition>> selectApiBaseInfoGroupByModuleId(String projectId, String protocol, String versionId, String status) {
List<ApiDefinition> apiList = extApiDefinitionMapper.selectApiBaseInfoByProjectIdAndProtocolAndStatus(projectId, protocol, versionId, status);
return apiList.stream().collect(Collectors.groupingBy(ApiDefinition::getModuleId));
}
/**
* 将模块删除了的接口模块改为默认模块
*
* @param projectId
* @param protocol
* @param status
* @param versionId
* @param id
*/
public void updateNoModuleApiToDefaultModule(String projectId, String protocol, String status, String versionId, String id) {
if (StringUtils.isNoneEmpty(projectId, protocol, id)) {
extApiDefinitionMapper.updateNoModuleApiToDefaultModule(projectId, protocol, status, versionId, id);
}
}
}

View File

@ -3,6 +3,7 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.ScenarioStatus;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.base.domain.*;
@ -41,6 +42,7 @@ import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@ -84,6 +86,58 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
return extApiModuleMapper.getNodeTreeByProjectId(projectId, protocol);
}
public List<ApiModuleDTO> getTrashNodeTreeByProtocolAndProjectId(String projectId, String protocol, String versionId) {
//回收站数据初始化检查是否存在模块被删除的接口则把接口挂再默认节点上
initTrashDataModule(projectId, protocol, versionId);
//通过回收站里的接口模块进行反显
Map<String, List<ApiDefinition>> trashApiMap = apiDefinitionService.selectApiBaseInfoGroupByModuleId(projectId, protocol, versionId, ScenarioStatus.Trash.name());
//查找回收站里的模块
List<ApiModuleDTO> trashModuleList = this.selectTreeStructModuleById(trashApiMap.keySet());
this.initApiCount(trashModuleList, trashApiMap);
return getNodeTrees(trashModuleList);
}
private void initApiCount(List<ApiModuleDTO> apiModules, Map<String, List<ApiDefinition>> trashApiMap) {
if (CollectionUtils.isNotEmpty(apiModules) && MapUtils.isNotEmpty(trashApiMap)) {
apiModules.forEach(node -> {
List<String> moduleIds = new ArrayList<>();
moduleIds = this.nodeList(apiModules, node.getId(), moduleIds);
moduleIds.add(node.getId());
int countNum = 0;
for (String moduleId : moduleIds) {
if (trashApiMap.containsKey(moduleId)) {
countNum += trashApiMap.get(moduleId).size();
}
}
node.setCaseNum(countNum);
});
}
}
private List<ApiModuleDTO> selectTreeStructModuleById(Collection<String> ids) {
if (CollectionUtils.isEmpty(ids)) {
return new ArrayList<>(0);
} else {
List<String> parentIdList = new ArrayList<>();
List<ApiModuleDTO> apiModuleList = extApiModuleMapper.selectByIds(ids);
apiModuleList.forEach(apiModuleDTO -> {
if (StringUtils.isNotBlank(apiModuleDTO.getParentId()) && !parentIdList.contains(apiModuleDTO.getParentId())) {
parentIdList.add(apiModuleDTO.getParentId());
}
});
apiModuleList.addAll(0, this.selectTreeStructModuleById(parentIdList));
List<ApiModuleDTO> returnList = new ArrayList<>(apiModuleList.stream().collect(Collectors.toMap(ApiModuleDTO::getId, Function.identity(), (t1, t2) -> t1)).values());
return returnList;
}
}
private void initTrashDataModule(String projectId, String protocol, String versionId) {
ApiModule defaultModule = this.getDefaultNode(projectId, protocol);
if (defaultModule != null) {
apiDefinitionService.updateNoModuleApiToDefaultModule(projectId, protocol, ScenarioStatus.Trash.name(), versionId, defaultModule.getId());
}
}
public List<ApiModuleDTO> getNodeTreeByProjectId(String projectId, String protocol, String versionId) {
// 判断当前项目下是否有默认模块没有添加默认模块
this.getDefaultNode(projectId, protocol);
@ -140,7 +194,7 @@ public class ApiModuleService extends NodeTreeService<ApiModuleDTO> {
if (moduleIdObj != null && countNumObj != null) {
String moduleId = String.valueOf(moduleIdObj);
try {
Integer countNumInteger = new Integer(String.valueOf(countNumObj));
Integer countNumInteger = Integer.parseInt(String.valueOf(countNumObj));
returnMap.put(moduleId, countNumInteger);
} catch (Exception e) {
LogUtil.error("method parseModuleCountList has error:", e);

View File

@ -22,6 +22,7 @@ import io.metersphere.service.NodeTreeService;
import io.metersphere.service.ProjectService;
import io.metersphere.track.service.TestPlanProjectService;
import io.metersphere.track.service.TestPlanScenarioCaseService;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
@ -34,6 +35,7 @@ import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@ -103,6 +105,58 @@ public class ApiScenarioModuleService extends NodeTreeService<ApiScenarioModuleD
return getNodeTrees(nodes);
}
public List<ApiScenarioModuleDTO> getTrashNodeTreeByProjectId(String projectId) {
//回收站数据初始化被删除了的数据挂在默认模块上
initTrashDataModule(projectId);
//通过回收站里的接口模块进行反显
Map<String, List<ApiScenario>> trashApiMap = apiAutomationService.selectApiBaseInfoGroupByModuleId(projectId, ScenarioStatus.Trash.name());
//查找回收站里的模块
List<ApiScenarioModuleDTO> trashModuleList = this.selectTreeStructModuleById(trashApiMap.keySet());
this.initApiCount(trashModuleList, trashApiMap);
return getNodeTrees(trashModuleList);
}
private void initApiCount(List<ApiScenarioModuleDTO> moduleDTOList, Map<String, List<ApiScenario>> scenarioMap) {
if (org.apache.commons.collections.CollectionUtils.isNotEmpty(moduleDTOList) && MapUtils.isNotEmpty(scenarioMap)) {
moduleDTOList.forEach(node -> {
List<String> moduleIds = new ArrayList<>();
moduleIds = this.nodeList(moduleDTOList, node.getId(), moduleIds);
moduleIds.add(node.getId());
int countNum = 0;
for (String moduleId : moduleIds) {
if (scenarioMap.containsKey(moduleId)) {
countNum += scenarioMap.get(moduleId).size();
}
}
node.setCaseNum(countNum);
});
}
}
private List<ApiScenarioModuleDTO> selectTreeStructModuleById(Collection<String> ids) {
if (org.apache.commons.collections.CollectionUtils.isEmpty(ids)) {
return new ArrayList<>(0);
} else {
List<String> parentIdList = new ArrayList<>();
List<ApiScenarioModuleDTO> apiModuleList = extApiScenarioModuleMapper.selectByIds(ids);
apiModuleList.forEach(apiModuleDTO -> {
if (StringUtils.isNotBlank(apiModuleDTO.getParentId()) && !parentIdList.contains(apiModuleDTO.getParentId())) {
parentIdList.add(apiModuleDTO.getParentId());
}
});
apiModuleList.addAll(0, this.selectTreeStructModuleById(parentIdList));
List<ApiScenarioModuleDTO> returnList = new ArrayList<>(apiModuleList.stream().collect(Collectors.toMap(ApiScenarioModuleDTO::getId, Function.identity(), (t1, t2) -> t1)).values());
return returnList;
}
}
private void initTrashDataModule(String projectId) {
ApiScenarioModule defaultModule = this.getDefaultNode(projectId);
if (defaultModule != null) {
apiAutomationService.updateNoModuleToDefaultModule(projectId, ScenarioStatus.Trash.name(), defaultModule.getId());
}
}
private Map<String, Integer> parseModuleCountList(List<Map<String, Object>> moduleCountList) {
Map<String, Integer> returnMap = new HashMap<>();
for (Map<String, Object> map : moduleCountList) {

View File

@ -106,4 +106,8 @@ public interface ExtApiDefinitionMapper {
List<ApiDefinition> selectEffectiveIdByProjectIdAndHaveNotCase(String projectId);
int deleteApiToGc(ApiDefinitionRequest request);
List<ApiDefinition> selectApiBaseInfoByProjectIdAndProtocolAndStatus(@Param("projectId") String projectId, @Param("protocol") String protocol, @Param("versionId") String versionId, @Param("status") String status);
void updateNoModuleApiToDefaultModule(@Param("projectId") String projectId, @Param("protocol") String protocol, @Param("status") String status, @Param("versionId") String versionId, @Param("moduleId") String moduleId);
}

View File

@ -1116,6 +1116,21 @@
</foreach>
</update>
<update id="updateNoModuleApiToDefaultModule">
UPDATE api_definition
SET module_id = #{moduleId}
WHERE protocol = #{protocol}
AND project_id = #{projectId}
<if test="status != null ">
AND status = #{status}
</if>
<if test="versionId != null ">
AND version_id = #{versionId}
</if>
AND module_id not in (
SELECT id FROM api_module WHERE project_id = #{projectId} AND protocol = #{protocol}
)
</update>
<select id="selectRefIdsForVersionChange" resultType="java.lang.String">
SELECT DISTINCT ref_id
FROM api_definition
@ -1173,6 +1188,16 @@
</foreach>
</if>
</select>
<select id="selectApiBaseInfoByProjectIdAndProtocolAndStatus" resultType="io.metersphere.base.domain.ApiDefinition">
select id, module_id
from api_definition
WHERE project_id = #{projectId}
AND protocol = #{protocol}
AND status = #{status}
<if test="versionId != null">
AND version_id = #{versionId}
</if>
</select>
<sql id="Same_Where_Clause">
<where>
<if test="blobs">

View File

@ -4,6 +4,7 @@ import io.metersphere.api.dto.definition.ApiModuleDTO;
import io.metersphere.base.domain.ApiModule;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
public interface ExtApiModuleMapper {
@ -11,6 +12,8 @@ public interface ExtApiModuleMapper {
List<ApiModuleDTO> getNodeTreeByProjectId(@Param("projectId") String projectId, @Param("protocol") String protocol);
List<ApiModuleDTO> selectByIds(@Param("ids") Collection<String> ids);
void updatePos(String id, Double pos);
String getNameById(String moduleId);

View File

@ -21,12 +21,27 @@
and api_module.protocol = #{protocol}
order by api_module.pos asc
</select>
<select id="selectByIds" resultType="io.metersphere.api.dto.definition.ApiModuleDTO">
select
<include refid="io.metersphere.base.mapper.ApiModuleMapper.Base_Column_List"/>
from api_module
where id IN
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
order by api_module.pos asc
</select>
<select id="getNameById" resultType="java.lang.String">
select name from api_module
select name
from api_module
where id = #{0}
</select>
<update id="updatePos">
update api_module set pos = #{pos} where id = #{id}
update api_module
set pos = #{pos}
where id = #{id}
</update>
</mapper>

View File

@ -94,4 +94,8 @@ public interface ExtApiScenarioMapper {
List<ApiScenarioWithBLOBs> selectRepeatByBLOBs(@Param("names") List<String> names, @Param("projectId") String projectId);
List<String> selectRelevanceIdsByQuery(@Param("request") BaseQueryRequest query);
void updateNoModuleToDefaultModule(@Param("projectId") String projectId, @Param("status") String status, @Param("moduleId") String moduleId);
List<ApiScenario> selectBaseInfoByProjectIdAndStatus(@Param("projectId") String projectId, @Param("status") String status);
}

View File

@ -827,5 +827,23 @@
<include refid="queryWhereCondition"/>
<include refid="io.metersphere.base.mapper.ext.ExtBaseMapper.orders"/>
</select>
</mapper>
<update id="updateNoModuleToDefaultModule">
UPDATE api_scenario
SET api_scenario_module_id = #{moduleId}
WHERE project_id = #{projectId}
<if test="status != null ">
AND status = #{status}
</if>
AND api_scenario_module_id not in (
SELECT id FROM api_scenario_module WHERE project_id = #{projectId}
)
</update>
<select id="selectBaseInfoByProjectIdAndStatus" resultType="io.metersphere.base.domain.ApiScenario">
select id, api_scenario_module_id
from api_scenario
WHERE project_id = #{projectId}
AND status = #{status}
AND latest IS TRUE
</select>
</mapper>

View File

@ -3,10 +3,13 @@ package io.metersphere.base.mapper.ext;
import io.metersphere.api.dto.automation.ApiScenarioModuleDTO;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
public interface ExtApiScenarioModuleMapper {
List<ApiScenarioModuleDTO> getNodeTreeByProjectId(@Param("projectId") String projectId);
void updatePos(String id, Double pos);
List<ApiScenarioModuleDTO> selectByIds(@Param("ids") Collection<String> ids);
}

View File

@ -10,6 +10,19 @@
</select>
<update id="updatePos">
update api_scenario_module set pos = #{pos} where id = #{id}
update api_scenario_module
set pos = #{pos}
where id = #{id}
</update>
<select id="selectByIds" resultType="io.metersphere.api.dto.automation.ApiScenarioModuleDTO">
select
<include refid="io.metersphere.base.mapper.ApiScenarioModuleMapper.Base_Column_List"/>
from api_scenario_module
where id IN
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
order by api_scenario_module.pos asc
</select>
</mapper>

View File

@ -5,6 +5,7 @@ import io.metersphere.base.domain.TestCaseNodeExample;
import io.metersphere.track.dto.ModuleNodeDTO;
import org.apache.ibatis.annotations.Param;
import java.util.Collection;
import java.util.List;
public interface ExtModuleNodeMapper {
@ -28,7 +29,7 @@ public interface ExtModuleNodeMapper {
ModuleNodeDTO get(@Param("tableName") String tableName, @Param("id") String id);
void updatePos(@Param("tableName") String tableName, @Param("id") String id, @Param("pos") Double pos);
void updatePos(@Param("tableName") String tableName, @Param("id") String id, @Param("pos") Double pos);
void updateByPrimaryKey(@Param("tableName") String tableName, @Param("record") ModuleNode record);
@ -36,5 +37,7 @@ public interface ExtModuleNodeMapper {
long countByExample(@Param("tableName") String tableName, @Param("example") TestCaseNodeExample example);
List<ModuleNode> selectByModulePath(@Param("tableName") String tableName,@Param("modulePath") String modulePath, @Param("projectId") String projectId);
List<ModuleNode> selectByModulePath(@Param("tableName") String tableName, @Param("modulePath") String modulePath, @Param("projectId") String projectId);
List<ModuleNodeDTO> selectByIds(@Param("tableName") String tableName, @Param("ids") Collection<String> ids);
}

View File

@ -2,139 +2,140 @@
<!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.ExtModuleNodeMapper">
<insert id="insertSelective">
insert into ${tableName}
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="record.id != null">
id,
</if>
<if test="record.projectId != null">
project_id,
</if>
<if test="record.name != null">
`name`,
</if>
<if test="record.modulePath != null">
`module_path`,
</if>
<if test="record.parentId != null">
parent_id,
</if>
<if test="record.level != null">
`level`,
</if>
<if test="record.createTime != null">
create_time,
</if>
<if test="record.updateTime != null">
update_time,
</if>
<if test="record.pos != null">
pos,
</if>
<if test="record.createUser != null">
create_user,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="record.id != null">
#{record.id,jdbcType=VARCHAR},
</if>
<if test="record.projectId != null">
#{record.projectId,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
#{record.name,jdbcType=VARCHAR},
</if>
<if test="record.modulePath != null">
#{record.modulePath,jdbcType=VARCHAR},
</if>
<if test="record.parentId != null">
#{record.parentId,jdbcType=VARCHAR},
</if>
<if test="record.level != null">
#{record.level,jdbcType=INTEGER},
</if>
<if test="record.createTime != null">
#{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
#{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.pos != null">
#{record.pos,jdbcType=DOUBLE},
</if>
<if test="record.createUser != null">
#{record.createUser,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<insert id="insert">
insert into ${tableName} (id, project_id, `name`,
parent_id, `level`, create_time,
update_time, pos, create_user
)
values (#{record.id,jdbcType=VARCHAR}, #{record.projectId,jdbcType=VARCHAR}, #{record.name,jdbcType=VARCHAR},
#{record.parentId,jdbcType=VARCHAR}, #{record.level,jdbcType=INTEGER}, #{record.createTime,jdbcType=BIGINT},
#{record.updateTime,jdbcType=BIGINT}, #{record.pos,jdbcType=DOUBLE}, #{record.createUser,jdbcType=VARCHAR}
)
</insert>
<insert id="insertWithModulePath">
insert into ${tableName} (id, project_id, `name`, module_path,
parent_id, `level`, create_time,
update_time, pos, create_user
)
values (#{record.id,jdbcType=VARCHAR}, #{record.projectId,jdbcType=VARCHAR}, #{record.name,jdbcType=VARCHAR}, #{record.modulePath,jdbcType=VARCHAR},
#{record.parentId,jdbcType=VARCHAR}, #{record.level,jdbcType=INTEGER}, #{record.createTime,jdbcType=BIGINT},
#{record.updateTime,jdbcType=BIGINT}, #{record.pos,jdbcType=DOUBLE}, #{record.createUser,jdbcType=VARCHAR}
)
</insert>
<update id="updateByPrimaryKeySelective">
update ${tableName}
<set>
<if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.modulePath != null">
`module_path` = #{record.modulePath,jdbcType=VARCHAR},
</if>
<if test="record.parentId != null">
parent_id = #{record.parentId,jdbcType=VARCHAR},
</if>
<if test="record.level != null">
`level` = #{record.level,jdbcType=INTEGER},
</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.pos != null">
pos = #{record.pos,jdbcType=DOUBLE},
</if>
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
</set>
where id = #{record.id,jdbcType=VARCHAR}
</update>
<insert id="insertSelective">
insert into ${tableName}
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="record.id != null">
id,
</if>
<if test="record.projectId != null">
project_id,
</if>
<if test="record.name != null">
`name`,
</if>
<if test="record.modulePath != null">
`module_path`,
</if>
<if test="record.parentId != null">
parent_id,
</if>
<if test="record.level != null">
`level`,
</if>
<if test="record.createTime != null">
create_time,
</if>
<if test="record.updateTime != null">
update_time,
</if>
<if test="record.pos != null">
pos,
</if>
<if test="record.createUser != null">
create_user,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="record.id != null">
#{record.id,jdbcType=VARCHAR},
</if>
<if test="record.projectId != null">
#{record.projectId,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
#{record.name,jdbcType=VARCHAR},
</if>
<if test="record.modulePath != null">
#{record.modulePath,jdbcType=VARCHAR},
</if>
<if test="record.parentId != null">
#{record.parentId,jdbcType=VARCHAR},
</if>
<if test="record.level != null">
#{record.level,jdbcType=INTEGER},
</if>
<if test="record.createTime != null">
#{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.updateTime != null">
#{record.updateTime,jdbcType=BIGINT},
</if>
<if test="record.pos != null">
#{record.pos,jdbcType=DOUBLE},
</if>
<if test="record.createUser != null">
#{record.createUser,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<insert id="insert">
insert into ${tableName} (id, project_id, `name`,
parent_id, `level`, create_time,
update_time, pos, create_user)
values (#{record.id,jdbcType=VARCHAR}, #{record.projectId,jdbcType=VARCHAR}, #{record.name,jdbcType=VARCHAR},
#{record.parentId,jdbcType=VARCHAR}, #{record.level,jdbcType=INTEGER},
#{record.createTime,jdbcType=BIGINT},
#{record.updateTime,jdbcType=BIGINT}, #{record.pos,jdbcType=DOUBLE},
#{record.createUser,jdbcType=VARCHAR})
</insert>
<insert id="insertWithModulePath">
insert into ${tableName} (id, project_id, `name`, module_path,
parent_id, `level`, create_time,
update_time, pos, create_user)
values (#{record.id,jdbcType=VARCHAR}, #{record.projectId,jdbcType=VARCHAR}, #{record.name,jdbcType=VARCHAR},
#{record.modulePath,jdbcType=VARCHAR},
#{record.parentId,jdbcType=VARCHAR}, #{record.level,jdbcType=INTEGER},
#{record.createTime,jdbcType=BIGINT},
#{record.updateTime,jdbcType=BIGINT}, #{record.pos,jdbcType=DOUBLE},
#{record.createUser,jdbcType=VARCHAR})
</insert>
<update id="updateByPrimaryKeySelective">
update ${tableName}
<set>
<if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
<if test="record.name != null">
`name` = #{record.name,jdbcType=VARCHAR},
</if>
<if test="record.modulePath != null">
`module_path` = #{record.modulePath,jdbcType=VARCHAR},
</if>
<if test="record.parentId != null">
parent_id = #{record.parentId,jdbcType=VARCHAR},
</if>
<if test="record.level != null">
`level` = #{record.level,jdbcType=INTEGER},
</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.pos != null">
pos = #{record.pos,jdbcType=DOUBLE},
</if>
<if test="record.createUser != null">
create_user = #{record.createUser,jdbcType=VARCHAR},
</if>
</set>
where id = #{record.id,jdbcType=VARCHAR}
</update>
<update id="updatePos">
update ${tableName}
set pos = #{pos}
where id = #{id}
</update>
<update id="updatePos">
update ${tableName}
set pos = #{pos}
where id = #{id}
</update>
<update id="updateByPrimaryKey">
update ${tableName}
set project_id = #{record.projectId,jdbcType=VARCHAR},
<update id="updateByPrimaryKey">
update ${tableName}
set project_id = #{record.projectId,jdbcType=VARCHAR},
`name` = #{record.name,jdbcType=VARCHAR},
<if test="record.modulePath != null">
`module_path` = #{record.modulePath,jdbcType=VARCHAR},
`module_path` = #{record.modulePath,jdbcType=VARCHAR},
</if>
parent_id = #{record.parentId,jdbcType=VARCHAR},
`level` = #{record.level,jdbcType=INTEGER},
@ -142,108 +143,122 @@
update_time = #{record.updateTime,jdbcType=BIGINT},
pos = #{record.pos,jdbcType=DOUBLE},
create_user = #{record.createUser,jdbcType=VARCHAR}
where id = #{record.id,jdbcType=VARCHAR}
</update>
where id = #{record.id,jdbcType=VARCHAR}
</update>
<delete id="deleteByExample">
delete from ${tableName}
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<select id="selectByExample" resultType="io.metersphere.base.domain.ModuleNode">
select
<if test="example.distinct">
distinct
</if>
<include refid="io.metersphere.base.mapper.TestCaseNodeMapper.Base_Column_List" />
,module_path
from ${tableName}
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="example.orderByClause != null">
order by ${example.orderByClause}
</if>
</select>
<select id="getNodeIdsByPid" resultType="java.lang.String">
select id
from ${tableName}
where parent_id = #{parentId}
</select>
<select id="getNodeTreeByProjectId" resultType="io.metersphere.track.dto.ModuleNodeDTO">
select
<include refid="io.metersphere.base.mapper.TestCaseNodeMapper.Base_Column_List"/>
from ${tableName}
where project_id = #{projectId}
order by pos asc
</select>
<select id="getAllNodeTree" resultType="io.metersphere.base.domain.ModuleNode">
select
id, project_id, `name`, parent_id, `level`, create_time, update_time, pos, create_user
,module_path
from ${tableName}
order by pos asc
</select>
<select id="get" resultType="io.metersphere.track.dto.ModuleNodeDTO">
select
<include refid="io.metersphere.base.mapper.TestCaseNodeMapper.Base_Column_List"/>
from ${tableName}
where id = #{id}
</select>
<select id="selectByPrimaryKey" resultType="io.metersphere.base.domain.ModuleNode">
select
*
from ${tableName}
where id = #{id,jdbcType=VARCHAR}
</select>
<select id="countByExample" resultType="java.lang.Long">
select count(*) from ${tableName}
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<sql id="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>
<delete id="deleteByExample">
delete from ${tableName}
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
</foreach>
</where>
</sql>
</delete>
<select id="selectByModulePath" resultType="io.metersphere.base.domain.ModuleNode" parameterType="io.metersphere.base.domain.ModuleNode">
SELECT
*
FROM
${tableName}
WHERE
project_id = #{projectId}
AND
module_path = #{modulePath}
</select>
<select id="selectByExample" resultType="io.metersphere.base.domain.ModuleNode">
select
<if test="example.distinct">
distinct
</if>
<include refid="io.metersphere.base.mapper.TestCaseNodeMapper.Base_Column_List"/>
,module_path
from ${tableName}
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
<if test="example.orderByClause != null">
order by ${example.orderByClause}
</if>
</select>
<select id="getNodeIdsByPid" resultType="java.lang.String">
select id
from ${tableName}
where parent_id = #{parentId}
</select>
<select id="getNodeTreeByProjectId" resultType="io.metersphere.track.dto.ModuleNodeDTO">
select
<include refid="io.metersphere.base.mapper.TestCaseNodeMapper.Base_Column_List"/>
from ${tableName}
where project_id = #{projectId}
order by pos asc
</select>
<select id="selectByIds" resultType="io.metersphere.track.dto.ModuleNodeDTO">
select
<include refid="io.metersphere.base.mapper.TestCaseNodeMapper.Base_Column_List"/>
from ${tableName}
where id IN
<foreach close=")" collection="ids" item="id" open="(" separator=",">
#{id}
</foreach>
order by pos asc
</select>
<select id="getAllNodeTree" resultType="io.metersphere.base.domain.ModuleNode">
select id
, project_id
, `name`
, parent_id
, `level`
, create_time
, update_time
, pos
, create_user
, module_path
from ${tableName}
order by pos asc
</select>
<select id="get" resultType="io.metersphere.track.dto.ModuleNodeDTO">
select
<include refid="io.metersphere.base.mapper.TestCaseNodeMapper.Base_Column_List"/>
from ${tableName}
where id = #{id}
</select>
<select id="selectByPrimaryKey" resultType="io.metersphere.base.domain.ModuleNode">
select *
from ${tableName}
where id = #{id,jdbcType=VARCHAR}
</select>
<select id="countByExample" resultType="java.lang.Long">
select count(*) from ${tableName}
<if test="_parameter != null">
<include refid="Example_Where_Clause"/>
</if>
</select>
<sql id="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>
<select id="selectByModulePath" resultType="io.metersphere.base.domain.ModuleNode"
parameterType="io.metersphere.base.domain.ModuleNode">
SELECT *
FROM ${tableName}
WHERE project_id = #{projectId}
AND module_path = #{modulePath}
</select>
</mapper>

View File

@ -13,15 +13,15 @@
@exportJmx="exportJmx"
@refreshAll="refreshAll"
page-source="scenario"
:is-trash-data="trashEnable"
:type="'edit'"
:total='total'
ref="nodeTree"/>
</ms-aside-container>
<ms-main-container style="overflow: hidden">
<el-tabs v-model="activeName" @tab-click="addTab" @tab-remove="closeConfirm">
<el-tab-pane
name="trash"
name="trash" :closable="true"
:label="$t('commons.trash')" v-if="trashEnable">
<ms-api-scenario-list
@getTrashCase="getTrashCase"
@ -47,6 +47,7 @@
</el-tab-pane>
<el-tab-pane name="default" :label="$t('api_test.automation.scenario_list')">
<ms-api-scenario-list
v-if="!trashEnable"
@getTrashCase="getTrashCase"
@refreshTree="refreshTree"
:module-tree="nodeTree"
@ -185,6 +186,9 @@ export default {
this.init();
},
watch: {
trashEnable() {
this.selectNodeIds = [];
},
redirectID() {
this.renderComponent = false;
this.$nextTick(() => {
@ -202,10 +206,12 @@ export default {
}
},
selectNodeIds() {
this.activeName = "default";
if (!this.trashEnable) {
this.activeName = "default";
}
},
activeName() {
this.isAsideHidden = this.activeName === 'default';
this.isAsideHidden = (this.activeName === 'default' || this.activeName === 'trash');
}
},
methods: {
@ -287,6 +293,7 @@ export default {
}
},
addTab(tab) {
this.trashEnable = tab.name === 'trash';
if (tab.name === 'default') {
this.$refs.apiScenarioList.search();
} else if (tab.name === 'trash') {
@ -361,6 +368,7 @@ export default {
callback: (action) => {
if (action === 'confirm') {
this.tabs = [];
this.trashEnable = false;
this.activeName = "default";
this.isSave = false;
// vuex
@ -372,6 +380,7 @@ export default {
});
} else {
this.tabs = [];
this.trashEnable = false;
this.activeName = "default";
this.refresh();
this.isSave = false;
@ -521,34 +530,39 @@ export default {
}
},
closeConfirm(targetName) {
let message = "";
this.tabs.forEach(tab => {
if (tab.name === targetName) {
this.diff(tab);
if (tab && this.isSave) {
message += tab.currentScenario.name ? tab.currentScenario.name : this.$t('api_test.automation.add_scenario');
}
}
})
if (message !== "") {
this.$alert(this.$t('commons.scenario') + " [ " + message + " ] " + this.$t('commons.confirm_info'), '', {
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),
callback: (action) => {
if (action === 'confirm') {
this.removeTab(targetName);
this.isSave = false;
} else {
this.isSave = false;
if (targetName === 'trash') {
this.selectNodeIds = [];
this.trashEnable = false;
} else {
let message = "";
this.tabs.forEach(tab => {
if (tab.name === targetName) {
this.diff(tab);
if (tab && this.isSave) {
message += tab.currentScenario.name ? tab.currentScenario.name : this.$t('api_test.automation.add_scenario');
}
}
});
} else {
this.isSave = false;
this.removeTab(targetName);
}
if (this.tabs && this.tabs.length === 0) {
this.refreshAll();
})
if (message !== "") {
this.$alert(this.$t('commons.scenario') + " [ " + message + " ] " + this.$t('commons.confirm_info'), '', {
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),
callback: (action) => {
if (action === 'confirm') {
this.removeTab(targetName);
this.isSave = false;
} else {
this.isSave = false;
}
}
});
} else {
this.isSave = false;
this.removeTab(targetName);
}
if (this.tabs && this.tabs.length === 0) {
this.refreshAll();
}
}
},
removeTab(targetName) {
@ -606,7 +620,9 @@ export default {
},
refreshAll() {
this.$refs.nodeTree.list();
this.$refs.apiScenarioList.search();
if (this.$refs.apiScenarioList) {
this.$refs.apiScenarioList.search();
}
if (this.$refs.apiTrashScenarioList) {
this.$refs.apiTrashScenarioList.search();
}

View File

@ -728,7 +728,6 @@ export default {
this.condition.moduleIds = this.selectNodeIds;
if (this.trashEnable) {
this.condition.filters = {status: ["Trash"]};
this.condition.moduleIds = [];
}
if (!this.condition.filters.status) {

View File

@ -14,6 +14,7 @@
:default-label="$t('api_test.automation.unplanned_scenario')"
local-suffix="api_scenario"
:show-case-num="showCaseNum"
:hide-opretor="isTrashData"
@add="add"
@edit="edit"
@drag="drag"
@ -28,7 +29,8 @@
:show-operator="showOperator"
:condition="condition"
:commands="operators"/>
<module-trash-button v-if="!isReadOnly" :condition="condition" :exe="enableTrash" :total='total'/>
<module-trash-button v-if="!isReadOnly && !isTrashData" :condition="condition" :exe="enableTrash"
:total='total'/>
</template>
</ms-node-tree>
@ -76,6 +78,7 @@ export default {
planId: String,
pageSource: String,
total: Number,
isTrashData: Boolean,
showCaseNum: {
type: Boolean,
default() {
@ -151,6 +154,10 @@ export default {
},
relevanceProjectId() {
this.list();
},
isTrashData() {
this.condition.trashEnable = this.isTrashData;
this.list();
}
},
methods: {
@ -176,6 +183,8 @@ export default {
url = '/api/automation/module/list/plan/' + this.planId;
} else if (this.isRelevanceModel) {
url = "/api/automation/module/list/" + this.relevanceProjectId;
} else if (this.isTrashData) {
url = "/api/automation/module/trash/list/" + (projectId ? projectId : this.projectId);
} else {
url = "/api/automation/module/list/" + (projectId ? projectId : this.projectId);
if (!this.projectId) {
@ -244,7 +253,6 @@ export default {
},
nodeChange(node, nodeIds, pNodes) {
this.currentModule = node.data;
this.condition.trashEnable = false;
if (node.data.id === 'root') {
this.$emit("nodeSelectEvent", node, [], pNodes);
} else {

View File

@ -16,6 +16,7 @@
@schedule="handleTabsEdit($t('api_test.api_import.timing_synchronization'), 'SCHEDULE')"
:type="'edit'"
page-source="definition"
:is-trash-data="trashEnable"
:total='total'
:current-version="currentVersion"
ref="nodeTree"/>
@ -30,9 +31,9 @@
class="ms-api-button"
ref="environmentSelect"/>
<!-- 主框架列表 -->
<el-tabs v-model="apiDefaultTab" @edit="closeConfirm" @tab-click="addTab">
<el-tabs v-model="apiDefaultTab" @edit="closeConfirm" @tab-click="addTab" @tab-remove="removeTab">
<el-tab-pane
name="trash"
name="trash" :closable="true"
:label="$t('commons.trash')" v-if="trashEnable">
<ms-tab-button
v-if="this.trashTabInfo.type === 'list'"
@ -110,7 +111,7 @@
</template>
<!-- 列表集合 -->
<ms-api-list
v-if="activeDom==='left'"
v-if="activeDom==='left' && !trashEnable"
@getTrashApi="getTrashApi"
:module-tree="nodeTree"
:module-options="moduleOptions"
@ -393,6 +394,9 @@ export default {
});
},
watch: {
trashEnable() {
this.selectNodeIds = [];
},
currentProtocol() {
if (this.activeDom === 'right') {
this.activeDom = 'left';
@ -400,7 +404,9 @@ export default {
this.handleCommand("CLOSE_ALL");
},
selectNodeIds() {
this.apiDefaultTab = "default";
if (!this.trashEnable) {
this.apiDefaultTab = "default";
}
},
redirectID() {
this.renderComponent = false;
@ -455,6 +461,12 @@ export default {
}
},
methods: {
removeTab(name) {
if (name === 'trash') {
this.selectNodeIds = [];
this.trashEnable = false;
}
},
openSwaggerScheduleTab() {
//
let scheduleTabName = "";
@ -519,6 +531,7 @@ export default {
this.redirectID = redirectIDParam;
},
addTab(tab) {
this.trashEnable = tab.name === 'trash';
if (tab.name === 'add') {
this.result = this.$get('/project_application/get/config/' + this.projectId + "/API_QUICK_MENU", res => {
let projectData = res.data;
@ -528,7 +541,6 @@ export default {
this.handleTabsEdit(this.$t('api_test.definition.request.fast_debug'), "debug");
}
})
} else if (tab.name === 'trash') {
if (this.$refs.trashApiList) {
this.$refs.trashApiList.initTable();
@ -620,6 +632,7 @@ export default {
if (action === 'confirm') {
this.$store.state.apiMap.clear();
this.apiTabs = [];
this.trashEnable = false;
this.apiDefaultTab = tabs.name;
this.apiTabs.push(tabs);
}
@ -627,6 +640,7 @@ export default {
});
} else {
this.apiTabs = [];
this.trashEnable = false;
this.apiDefaultTab = tabs.name;
this.apiTabs.push(tabs);
}

View File

@ -525,14 +525,12 @@ export default {
},
watch: {
selectNodeIds() {
if (!this.trashEnable) {
initCondition(this.condition, false);
this.currentPage = 1;
this.condition.moduleIds = [];
this.condition.moduleIds.push(this.selectNodeIds);
this.closeCaseModel();
this.initTable();
}
initCondition(this.condition, false);
this.currentPage = 1;
this.condition.moduleIds = [];
this.condition.moduleIds.push(this.selectNodeIds);
this.closeCaseModel();
this.initTable();
},
currentProtocol() {
this.getProtocolFilter();
@ -617,9 +615,7 @@ export default {
initCondition(this.condition, this.condition.selectAll);
this.selectDataCounts = 0;
if (!this.trashEnable) {
this.condition.moduleIds = this.selectNodeIds;
}
this.condition.moduleIds = this.selectNodeIds;
this.condition.projectId = this.projectId;
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;

View File

@ -9,6 +9,7 @@
:type="isReadOnly ? 'view' : 'edit'"
:allLabel="$t('api_test.definition.api_all')"
:default-label="$t('api_test.definition.unplanned_api')"
:hide-opretor="isTrashData"
local-suffix="api_definition"
@add="add"
@edit="edit"
@ -32,6 +33,7 @@
:moduleOptions="data"
:options="options"
:total="total"
:is-trash-data="isTrashData"
@exportAPI="exportAPI"
@saveAsEdit="saveAsEdit"
@refreshTable="$emit('refreshTable')"
@ -90,6 +92,12 @@ export default {
return true;
}
},
isTrashData: {
type: Boolean,
default() {
return false;
}
},
showOperator: Boolean,
planId: String,
currentVersion: String,
@ -142,6 +150,10 @@ export default {
},
reviewId() {
this.list();
},
isTrashData() {
this.condition.trashEnable = this.isTrashData;
this.list();
}
},
methods: {
@ -200,6 +212,9 @@ export default {
} else if (this.isRelevanceModel) {
url = "/api/module/list/" + this.relevanceProjectId + "/" + this.condition.protocol +
(this.currentVersion ? '/' + this.currentVersion : '');
} else if (this.isTrashData) {
url = "/api/module/trash/list/" + (projectId ? projectId : this.projectId) + "/" + this.condition.protocol +
(this.currentVersion ? '/' + this.currentVersion : '');
} else {
url = "/api/module/list/" + (projectId ? projectId : this.projectId) + "/" + this.condition.protocol +
(this.currentVersion ? '/' + this.currentVersion : '');
@ -268,7 +283,6 @@ export default {
},
nodeChange(node, nodeIds, pNodes) {
this.currentModule = node.data;
this.condition.trashEnable = false;
if (node.data.id === 'root') {
this.$emit("nodeSelectEvent", node, [], pNodes);
} else {

View File

@ -20,7 +20,8 @@
</el-col>
</el-row>
<module-trash-button v-if="!isReadOnly" :condition="condition" :total="total" :exe="enableTrash"/>
<module-trash-button v-if="showTrashNode" :condition="condition" :total="total"
:exe="enableTrash"/>
<ms-add-basis-api
:current-protocol="condition.protocol"
@ -167,6 +168,12 @@ export default {
return false;
}
},
isTrashData: {
type: Boolean,
default() {
return false;
}
},
options: {
type: Array,
default() {
@ -178,6 +185,9 @@ export default {
projectId() {
return getCurrentProjectID();
},
showTrashNode() {
return (!this.isReadOnly && !this.isTrashData);
}
},
watch: {
'condition.protocol'() {
@ -186,7 +196,7 @@ export default {
} else {
this.operators = this.otherOperators;
}
}
},
},
created() {
this.operators = this.httpOperators;

View File

@ -38,7 +38,7 @@
</span>
<span v-if="!disabled" class="node-operate child">
<el-tooltip
v-if="data.id !== 'root' && data.name !== defaultLabel"
v-if="data.id !== 'root' && data.name !== defaultLabel && !hideOpretor"
class="item"
effect="dark"
v-permission="updatePermission"
@ -48,7 +48,7 @@
<i @click.stop="edit(node, data)" class="el-icon-edit"></i>
</el-tooltip>
<el-tooltip
v-if="data.name === defaultLabel && data.level !== 1"
v-if="data.name === defaultLabel && data.level !== 1 && !hideOpretor"
v-permission="updatePermission"
class="item"
effect="dark"
@ -62,14 +62,14 @@
effect="dark"
:open-delay="200"
v-permission="addPermission"
v-if="!isDefault(data)"
v-if="!isDefault(data) && !hideOpretor"
:content="$t('test_track.module.add_submodule')"
placement="top">
<i @click.stop="append(node, data)" class="el-icon-circle-plus-outline"></i>
</el-tooltip>
<el-tooltip
v-if="data.name === defaultLabel && data.level !==1"
v-if="data.name === defaultLabel && data.level !==1 && !hideOpretor"
class="item" effect="dark"
:open-delay="200"
v-permission="deletePermission"
@ -79,7 +79,7 @@
</el-tooltip>
<el-tooltip
v-if="data.id !== 'root' && data.name !== defaultLabel"
v-if="data.id !== 'root' && data.name !== defaultLabel && !hideOpretor"
class="item" effect="dark"
:open-delay="200"
:content="$t('commons.delete')"
@ -159,7 +159,8 @@ export default {
updatePermission: Array,
addPermission: Array,
deletePermission: Array,
localSuffix: String
localSuffix: String,
hideOpretor: Boolean,
},
watch: {
treeNodes() {