feat(用例评审): 新增单独取消关联功能用例获取评审模块数量接口

This commit is contained in:
guoyuqi 2023-12-12 11:13:18 +08:00 committed by Craftsman
parent a236a424bb
commit 18fce82f90
7 changed files with 254 additions and 2 deletions

View File

@ -29,6 +29,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
import java.util.Map;
@Tag(name = "用例管理-用例评审") @Tag(name = "用例管理-用例评审")
@RestController @RestController
@ -39,14 +40,21 @@ public class CaseReviewController {
private CaseReviewService caseReviewService; private CaseReviewService caseReviewService;
@PostMapping("/page") @PostMapping("/page")
@Operation(summary = "用例管理-功能用例-用例列表查询") @Operation(summary = "用例管理-用例评审-用例列表查询")
@RequiresPermissions(PermissionConstants.FUNCTIONAL_CASE_READ) @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ)
public Pager<List<CaseReviewDTO>> getFunctionalCasePage(@Validated @RequestBody CaseReviewPageRequest request) { public Pager<List<CaseReviewDTO>> getFunctionalCasePage(@Validated @RequestBody CaseReviewPageRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(),
StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "pos desc"); StringUtils.isNotBlank(request.getSortString()) ? request.getSortString() : "pos desc");
return PageUtils.setPageInfo(page, caseReviewService.getCaseReviewPage(request)); return PageUtils.setPageInfo(page, caseReviewService.getCaseReviewPage(request));
} }
@PostMapping("/module/count")
@Operation(summary = "用例管理-用例评审-表格分页查询文件")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ)
public Map<String, Long> moduleCount(@Validated @RequestBody CaseReviewPageRequest request) {
return caseReviewService.moduleCount(request);
}
@PostMapping("/add") @PostMapping("/add")
@Operation(summary = "用例管理-用例评审-创建用例评审") @Operation(summary = "用例管理-用例评审-创建用例评审")
@Log(type = OperationLogType.ADD, expression = "#msClass.addCaseReviewLog(#request)", msClass = CaseReviewLogService.class) @Log(type = OperationLogType.ADD, expression = "#msClass.addCaseReviewLog(#request)", msClass = CaseReviewLogService.class)
@ -97,6 +105,14 @@ public class CaseReviewController {
caseReviewService.associateCase(request, SessionUtils.getUserId()); caseReviewService.associateCase(request, SessionUtils.getUserId());
} }
@GetMapping("disassociate/{reviewId}/{caseId}")
@Operation(summary = "用例管理-用例评审-取消关联用例")
@Log(type = OperationLogType.DISASSOCIATE, expression = "#msClass.disAssociateCaseLog(#reviewId, #caseId)", msClass = CaseReviewLogService.class)
@RequiresPermissions(PermissionConstants.CASE_REVIEW_RELEVANCE)
public void disassociate(@PathVariable String reviewId, @PathVariable String caseId) {
caseReviewService.disassociate(reviewId, caseId);
}
@PostMapping("/edit/pos") @PostMapping("/edit/pos")
@Operation(summary = "用例管理-用例评审-拖拽排序") @Operation(summary = "用例管理-用例评审-拖拽排序")
@RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_UPDATE) @RequiresPermissions(PermissionConstants.CASE_REVIEW_READ_UPDATE)

View File

@ -4,6 +4,7 @@ import io.metersphere.functional.domain.CaseReview;
import io.metersphere.functional.dto.CaseReviewDTO; import io.metersphere.functional.dto.CaseReviewDTO;
import io.metersphere.functional.request.CaseReviewBatchRequest; import io.metersphere.functional.request.CaseReviewBatchRequest;
import io.metersphere.functional.request.CaseReviewPageRequest; import io.metersphere.functional.request.CaseReviewPageRequest;
import io.metersphere.project.dto.ModuleCountDTO;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -26,4 +27,10 @@ public interface ExtCaseReviewMapper {
List<String> getIds(@Param("request") CaseReviewBatchRequest request, @Param("projectId") String projectId); List<String> getIds(@Param("request") CaseReviewBatchRequest request, @Param("projectId") String projectId);
void batchMoveModule(@Param("request") CaseReviewBatchRequest request, @Param("ids") List<String> ids, @Param("userId") String userId); void batchMoveModule(@Param("request") CaseReviewBatchRequest request, @Param("ids") List<String> ids, @Param("userId") String userId);
List<ModuleCountDTO> countModuleIdByKeywordAndFileType(@Param("request") CaseReviewPageRequest request);
long caseCount(@Param("request") CaseReviewPageRequest request);
} }

View File

@ -116,6 +116,21 @@
<property name="searchMode" value="request.searchMode"/> <property name="searchMode" value="request.searchMode"/>
</include> </include>
</if> </if>
<if test="request.createByMe != null">
case_review.create_user = #{request.createByMe}
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<if test="request.reviewByMe != null">
case_review.id in
(
select case_review_user.review_id from case_review_user where case_review_user.user_id = #{request.reviewByMe}
)
<include refid="queryType">
<property name="searchMode" value="request.searchMode"/>
</include>
</if>
<include refid="filters"> <include refid="filters">
<property name="filter" value="request.filter"/> <property name="filter" value="request.filter"/>
</include> </include>
@ -373,4 +388,40 @@
</foreach> </foreach>
</update> </update>
<select id="countModuleIdByKeywordAndFileType" resultType="io.metersphere.project.dto.ModuleCountDTO">
SELECT module_id AS moduleId, count(id) AS dataCount
FROM case_review
WHERE project_id = #{request.projectId}
<choose>
<when test='request.searchMode == "AND"'>
AND <include refid="queryWhereCondition"/>
</when>
<when test='request.searchMode == "OR"'>
AND (
<include refid="queryWhereCondition"/>
)
</when>
</choose>
1 = 1
GROUP BY moduleId
</select>
<select id="caseCount"
resultType="java.lang.Long">
SELECT count(id)
FROM case_review
WHERE project_id = #{request.projectId}
<choose>
<when test='request.searchMode == "AND"'>
AND <include refid="queryWhereCondition"/>
</when>
<when test='request.searchMode == "OR"'>
and (
<include refid="queryWhereCondition"/>
)
</when>
</choose>
1 = 1
</select>
</mapper> </mapper>

View File

@ -22,4 +22,12 @@ public class CaseReviewPageRequest extends BasePageRequest implements Serializab
@Schema(description = "模块id") @Schema(description = "模块id")
private List<String> moduleIds; private List<String> moduleIds;
@Schema(description = "我评审的")
private String reviewByMe;
@Schema(description = "我创建的")
private String createByMe;
} }

View File

@ -164,11 +164,36 @@ public class CaseReviewLogService {
dto.setPath("/case/review/associate"); dto.setPath("/case/review/associate");
dto.setMethod(HttpMethodConstants.POST.name()); dto.setMethod(HttpMethodConstants.POST.name());
dto.setOriginalValue(JSON.toJSONBytes(functionalCase)); dto.setOriginalValue(JSON.toJSONBytes(functionalCase));
dtoList.add(dto);
} }
return dtoList; return dtoList;
} }
public LogDTO disAssociateCaseLog(String reviewId, String caseId) {
CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(reviewId);
if (caseReview == null) {
return null;
}
FunctionalCase functionalCase = functionalCaseMapper.selectByPrimaryKey(caseId);
if (functionalCase == null) {
return null;
}
LogDTO dto = new LogDTO(
caseReview.getProjectId(),
null,
caseReview.getId(),
null,
OperationLogType.DISASSOCIATE.name(),
OperationLogModule.CASE_REVIEW,
functionalCase.getName());
dto.setPath("/case/review/disassociate");
dto.setMethod(HttpMethodConstants.GET.name());
dto.setOriginalValue(JSON.toJSONBytes(functionalCase));
return dto;
}
public List<LogDTO> batchDisassociateCaseLog(BaseReviewCaseBatchRequest request) { public List<LogDTO> batchDisassociateCaseLog(BaseReviewCaseBatchRequest request) {
List<String> ids = caseReviewFunctionalCaseService.doSelectIds(request); List<String> ids = caseReviewFunctionalCaseService.doSelectIds(request);

View File

@ -12,6 +12,7 @@ import io.metersphere.functional.request.CaseReviewBatchRequest;
import io.metersphere.functional.request.CaseReviewPageRequest; import io.metersphere.functional.request.CaseReviewPageRequest;
import io.metersphere.functional.request.CaseReviewRequest; import io.metersphere.functional.request.CaseReviewRequest;
import io.metersphere.functional.result.CaseManagementResultCode; import io.metersphere.functional.result.CaseManagementResultCode;
import io.metersphere.project.dto.ModuleCountDTO;
import io.metersphere.sdk.constants.ApplicationNumScope; import io.metersphere.sdk.constants.ApplicationNumScope;
import io.metersphere.sdk.constants.PermissionConstants; import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.exception.MSException;
@ -71,8 +72,14 @@ public class CaseReviewService {
private FunctionalCaseMapper functionalCaseMapper; private FunctionalCaseMapper functionalCaseMapper;
@Resource @Resource
private DeleteCaseReviewService deleteCaseReviewService; private DeleteCaseReviewService deleteCaseReviewService;
@Resource
private CaseReviewFunctionalCaseUserMapper caseReviewFunctionalCaseUserMapper;
@Resource
private CaseReviewModuleService caseReviewModuleService;
private static final String CASE_MODULE_COUNT_ALL = "all";
/** /**
* 获取用例评审列表 * 获取用例评审列表
* *
@ -523,4 +530,45 @@ public class CaseReviewService {
deleteCaseReviewService.deleteCaseReviewResource(List.of(reviewId), projectId, false); deleteCaseReviewService.deleteCaseReviewResource(List.of(reviewId), projectId, false);
} }
public void disassociate(String reviewId, String caseId) {
//1.刪除评审与功能用例关联关系
CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(reviewId).andCaseIdEqualTo(caseId);
caseReviewFunctionalCaseMapper.deleteByExample(caseReviewFunctionalCaseExample);
//2.删除用例和用例评审人的关系
CaseReviewFunctionalCaseUserExample caseReviewFunctionalCaseUserExample = new CaseReviewFunctionalCaseUserExample();
caseReviewFunctionalCaseUserExample.createCriteria().andCaseIdEqualTo(caseId).andReviewIdEqualTo(reviewId);
caseReviewFunctionalCaseUserMapper.deleteByExample(caseReviewFunctionalCaseUserExample);
caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(reviewId);
List<CaseReviewFunctionalCase> caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample);
List<CaseReviewFunctionalCase> passList = caseReviewFunctionalCases.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getStatus(), FunctionalCaseReviewStatus.PASS.toString())).toList();
CaseReview caseReview = new CaseReview();
caseReview.setId(reviewId);
//更新用例数量
caseReview.setCaseCount(caseReviewFunctionalCases.size());
//通过率
BigDecimal passCount = BigDecimal.valueOf(passList.size());
BigDecimal totalCount = BigDecimal.valueOf(caseReview.getCaseCount());
BigDecimal passRate;
if (totalCount.compareTo(BigDecimal.ZERO)==0) {
passRate = BigDecimal.ZERO;
} else {
passRate = passCount.divide(totalCount, 2, RoundingMode.HALF_UP);
}
caseReview.setPassRate(passRate);
caseReviewMapper.updateByPrimaryKeySelective(caseReview);
}
public Map<String, Long> moduleCount(CaseReviewPageRequest request) {
//查出每个模块节点下的资源数量 不需要按照模块进行筛选
List<ModuleCountDTO> moduleCountDTOList = extCaseReviewMapper.countModuleIdByKeywordAndFileType(request);
Map<String, Long> moduleCountMap = caseReviewModuleService.getModuleCountMap(request.getProjectId(), moduleCountDTOList);
//查出全部用例数量
long allCount = extCaseReviewMapper.caseCount(request);
moduleCountMap.put(CASE_MODULE_COUNT_ALL, allCount);
return moduleCountMap;
}
} }

View File

@ -32,6 +32,7 @@ import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils; import org.testcontainers.shaded.org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -54,7 +55,9 @@ public class CaseReviewControllerTests extends BaseTest {
private static final String BATCH_MOVE_CASE_REVIEW = "/case/review/batch/move"; private static final String BATCH_MOVE_CASE_REVIEW = "/case/review/batch/move";
private static final String EDIT_CASE_REVIEW = "/case/review/edit"; private static final String EDIT_CASE_REVIEW = "/case/review/edit";
private static final String PAGE_CASE_REVIEW = "/case/review/page"; private static final String PAGE_CASE_REVIEW = "/case/review/page";
private static final String MODULE_COUNT_CASE_REVIEW = "/case/review/module/count";
private static final String ASSOCIATE_CASE_REVIEW = "/case/review/associate"; private static final String ASSOCIATE_CASE_REVIEW = "/case/review/associate";
private static final String DISASSOCIATE_CASE_REVIEW = "/case/review/disassociate/";
private static final String EDIT_POS_CASE_REVIEW_URL = "/case/review/edit/pos"; private static final String EDIT_POS_CASE_REVIEW_URL = "/case/review/edit/pos";
private static final String FOLLOW_CASE_REVIEW = "/case/review/edit/follower"; private static final String FOLLOW_CASE_REVIEW = "/case/review/edit/follower";
private static final String CASE_REVIEWER_LIST = "/case/review/user-option/"; private static final String CASE_REVIEWER_LIST = "/case/review/user-option/";
@ -339,9 +342,19 @@ public class CaseReviewControllerTests extends BaseTest {
request.setCombine(caseReviewCombine); request.setCombine(caseReviewCombine);
request.setProjectId(projectId); request.setProjectId(projectId);
request.setKeyword("评审更新"); request.setKeyword("评审更新");
request.setReviewByMe("admin");
request.setCurrent(1); request.setCurrent(1);
request.setPageSize(10); request.setPageSize(10);
MvcResult mvcResult = this.requestPostWithOkAndReturn(PAGE_CASE_REVIEW, request); MvcResult mvcResult = this.requestPostWithOkAndReturn(PAGE_CASE_REVIEW, request);
Pager<List<CaseReviewDTO>> tableData = JSON.parseObject(JSON.toJSONString(
JSON.parseObject(mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()),
Pager.class);
MvcResult moduleCountMvcResult = this.requestPostWithOkAndReturn(MODULE_COUNT_CASE_REVIEW, request);
Map<String, Integer> moduleCount = JSON.parseObject(JSON.toJSONString(
JSON.parseObject(moduleCountMvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8), ResultHolder.class).getData()),
Map.class);
// 获取返回值 // 获取返回值
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8); String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class); ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
@ -355,6 +368,21 @@ public class CaseReviewControllerTests extends BaseTest {
// 返回的数据量不超过规定要返回的数据量相同 // 返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= request.getPageSize()); Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= request.getPageSize());
//如果没有数据则返回的模块节点也不应该有数据
boolean moduleHaveResource = false;
for (int countByModuleId : moduleCount.values()) {
if (countByModuleId > 0) {
moduleHaveResource = true;
break;
}
}
Assertions.assertEquals(request.getPageSize(), tableData.getPageSize());
if (tableData.getTotal() > 0) {
Assertions.assertTrue(moduleHaveResource);
}
Assertions.assertTrue(moduleCount.containsKey("all"));
CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample(); CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviews.get(0).getId()); caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviews.get(0).getId());
List<CaseReviewFunctionalCase> caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample); List<CaseReviewFunctionalCase> caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample);
@ -507,6 +535,75 @@ public class CaseReviewControllerTests extends BaseTest {
Assertions.assertEquals(1, notifications.size()); Assertions.assertEquals(1, notifications.size());
} }
@Test
@Order(17)
public void testDisassociate() throws Exception {
List<CaseReview> caseReviews = getCaseReviews("创建评审更新1");
Assertions.assertEquals(1, caseReviews.size());
String caseReviewId = caseReviews.get(0).getId();
CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviewId).andCaseIdEqualTo("CASE_REVIEW_TEST_GYQ_ID6");
List<CaseReviewFunctionalCase> caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample);
Assertions.assertEquals(1, caseReviewFunctionalCases.size());
mockMvc.perform(MockMvcRequestBuilders.get(DISASSOCIATE_CASE_REVIEW+caseReviewId+"/CASE_REVIEW_TEST_GYQ_ID6").header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(SessionConstants.CURRENT_PROJECT, projectId)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample();
caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviewId).andCaseIdEqualTo("CASE_REVIEW_TEST_GYQ_ID6");
caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample);
Assertions.assertEquals(0, caseReviewFunctionalCases.size());
caseReviews = getCaseReviews("创建评审3");
Assertions.assertEquals(1, caseReviews.size());
caseReviewId = caseReviews.get(0).getId();
CaseReviewAssociateRequest caseReviewAssociateRequest = new CaseReviewAssociateRequest();
caseReviewAssociateRequest.setProjectId(projectId);
caseReviewAssociateRequest.setReviewId(caseReviewId);
List<String> caseIds = new ArrayList<>();
caseIds.add("CASE_REVIEW_TEST_GYQ_ID2");
caseReviewAssociateRequest.setCaseIds(caseIds);
List<String> userIds = new ArrayList<>();
userIds.add("gyq_review_test");
userIds.add("gyq_review_test2");
caseReviewAssociateRequest.setReviewers(userIds);
this.requestPostWithOk(ASSOCIATE_CASE_REVIEW, caseReviewAssociateRequest);
mockMvc.perform(MockMvcRequestBuilders.get(DISASSOCIATE_CASE_REVIEW+caseReviewId+"/CASE_REVIEW_TEST_GYQ_ID2").header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(SessionConstants.CURRENT_PROJECT, projectId)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(caseReviewId);
Assertions.assertEquals(0, caseReview.getPassRate().compareTo(BigDecimal.ZERO));
}
@Test
@Order(18)
public void testDisassociateFalse() throws Exception {
List<CaseReview> caseReviews = getCaseReviews("创建评审更新1");
mockMvc.perform(MockMvcRequestBuilders.get(DISASSOCIATE_CASE_REVIEW+"caseReviewIdX"+"/CASE_REVIEW_TEST_GYQ_ID6").header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(SessionConstants.CURRENT_PROJECT, projectId)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
String caseReviewId = caseReviews.get(0).getId();
mockMvc.perform(MockMvcRequestBuilders.get(DISASSOCIATE_CASE_REVIEW+caseReviewId+"/CASE_REVIEW_TEST_GYQ_IDXX").header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.header(SessionConstants.CURRENT_PROJECT, projectId)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
}
/** /**
* 生成高级搜索参数 * 生成高级搜索参数
* *