feat(用例管理): 评审标准为多人评审的用例评审,用例评审详新增我的评审状态筛选条件前后端接口代码

This commit is contained in:
WangXu10 2024-02-06 16:56:21 +08:00 committed by Craftsman
parent cb3d2ed2ea
commit cd1e8d3ca4
12 changed files with 121 additions and 42 deletions

View File

@ -58,4 +58,7 @@ public class ReviewFunctionalCaseDTO implements Serializable {
@Schema(description = "用例创建人名称") @Schema(description = "用例创建人名称")
private String createUserName; private String createUserName;
@Schema(description = "只看我的评审状态")
private String myStatus;
} }

View File

@ -1,5 +1,6 @@
package io.metersphere.functional.mapper; package io.metersphere.functional.mapper;
import io.metersphere.functional.domain.CaseReviewHistory;
import io.metersphere.functional.dto.CaseReviewHistoryDTO; import io.metersphere.functional.dto.CaseReviewHistoryDTO;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
@ -19,4 +20,6 @@ public interface ExtCaseReviewHistoryMapper {
void updateAbandoned(@Param("caseId") String caseId); void updateAbandoned(@Param("caseId") String caseId);
void batchUpdateAbandoned(@Param("reviewId") String reviewId, @Param("caseIds") List<String> caseIds); void batchUpdateAbandoned(@Param("reviewId") String reviewId, @Param("caseIds") List<String> caseIds);
List<CaseReviewHistory> getReviewHistoryStatus(@Param("caseIds") List<String> caseIds, @Param("reviewId") String reviewId);
} }

View File

@ -79,4 +79,23 @@
and abandoned = false and abandoned = false
</update> </update>
<select id="getReviewHistoryStatus" resultType="io.metersphere.functional.domain.CaseReviewHistory">
SELECT
review_id,
case_id,
STATUS,
create_user
FROM
case_review_history
WHERE
review_id = #{reviewId}
AND case_id IN
<foreach collection="caseIds" item="caseId" separator="," open="(" close=")">
#{caseId}
</foreach>
AND abandoned = FALSE
order by create_time desc
</select>
</mapper> </mapper>

View File

@ -30,4 +30,7 @@ public class ReviewFunctionalCasePageRequest extends BasePageRequest implements
@Schema(description = "模块id") @Schema(description = "模块id")
private List<String> moduleIds; private List<String> moduleIds;
@Schema(description = "我的评审结果", requiredMode = Schema.RequiredMode.REQUIRED)
private boolean viewStatusFlag;
} }

View File

@ -123,10 +123,10 @@ public class CaseReviewFunctionalCaseService {
*/ */
public List<ReviewFunctionalCaseDTO> page(ReviewFunctionalCasePageRequest request, boolean deleted, String userId) { public List<ReviewFunctionalCaseDTO> page(ReviewFunctionalCasePageRequest request, boolean deleted, String userId) {
List<ReviewFunctionalCaseDTO> list = extCaseReviewFunctionalCaseMapper.page(request, deleted, userId, request.getSortString()); List<ReviewFunctionalCaseDTO> list = extCaseReviewFunctionalCaseMapper.page(request, deleted, userId, request.getSortString());
return doHandleDTO(list, request.getReviewId()); return doHandleDTO(list, request, userId);
} }
private List<ReviewFunctionalCaseDTO> doHandleDTO(List<ReviewFunctionalCaseDTO> list, String reviewId) { private List<ReviewFunctionalCaseDTO> doHandleDTO(List<ReviewFunctionalCaseDTO> list, ReviewFunctionalCasePageRequest request, String userId) {
if (CollectionUtils.isNotEmpty(list)) { if (CollectionUtils.isNotEmpty(list)) {
List<String> moduleIds = list.stream().map(ReviewFunctionalCaseDTO::getModuleId).toList(); List<String> moduleIds = list.stream().map(ReviewFunctionalCaseDTO::getModuleId).toList();
List<BaseTreeNode> modules = extFunctionalCaseModuleMapper.selectBaseByIds(moduleIds); List<BaseTreeNode> modules = extFunctionalCaseModuleMapper.selectBaseByIds(moduleIds);
@ -137,20 +137,57 @@ public class CaseReviewFunctionalCaseService {
Map<String, String> versionMap = versions.stream().collect(Collectors.toMap(ProjectVersion::getId, ProjectVersion::getName)); Map<String, String> versionMap = versions.stream().collect(Collectors.toMap(ProjectVersion::getId, ProjectVersion::getName));
List<String> caseIds = list.stream().map(ReviewFunctionalCaseDTO::getCaseId).toList(); List<String> caseIds = list.stream().map(ReviewFunctionalCaseDTO::getCaseId).toList();
List<ReviewsDTO> reviewers = extCaseReviewFunctionalCaseUserMapper.selectReviewers(caseIds, reviewId); List<ReviewsDTO> reviewers = extCaseReviewFunctionalCaseUserMapper.selectReviewers(caseIds, request.getReviewId());
Map<String, String> userIdMap = reviewers.stream().collect(Collectors.toMap(ReviewsDTO::getCaseId, ReviewsDTO::getUserIds)); Map<String, String> userIdMap = reviewers.stream().collect(Collectors.toMap(ReviewsDTO::getCaseId, ReviewsDTO::getUserIds));
Map<String, String> userNameMap = reviewers.stream().collect(Collectors.toMap(ReviewsDTO::getCaseId, ReviewsDTO::getUserNames)); Map<String, String> userNameMap = reviewers.stream().collect(Collectors.toMap(ReviewsDTO::getCaseId, ReviewsDTO::getUserNames));
LinkedHashMap<String, List<CaseReviewHistory>> caseStatusMap;
LinkedHashMap<String, List<CaseReviewHistory>> caseUserMap;
if (request.isViewStatusFlag()) {
List<CaseReviewHistory> histories = extCaseReviewHistoryMapper.getReviewHistoryStatus(caseIds, request.getReviewId());
caseStatusMap = histories.stream().collect(Collectors.groupingBy(CaseReviewHistory::getCaseId, LinkedHashMap::new, Collectors.toList()));
caseUserMap = histories.stream().collect(Collectors.groupingBy(CaseReviewHistory::getCreateUser, LinkedHashMap::new, Collectors.toList()));
} else {
caseStatusMap = new LinkedHashMap<>();
caseUserMap = new LinkedHashMap<>();
}
//当前用户的评审历史
List<CaseReviewHistory> userHistory = caseUserMap.get(userId);
list.forEach(item -> { list.forEach(item -> {
item.setModuleName(moduleMap.get(item.getModuleId())); item.setModuleName(moduleMap.get(item.getModuleId()));
item.setVersionName(versionMap.get(item.getVersionId())); item.setVersionName(versionMap.get(item.getVersionId()));
item.setReviewers(Collections.singletonList(userIdMap.get(item.getCaseId()))); item.setReviewers(Collections.singletonList(userIdMap.get(item.getCaseId())));
item.setReviewNames(Collections.singletonList(userNameMap.get(item.getCaseId()))); item.setReviewNames(Collections.singletonList(userNameMap.get(item.getCaseId())));
if (request.isViewStatusFlag()) {
List<CaseReviewHistory> histories = caseStatusMap.get(item.getCaseId());
if (CollectionUtils.isNotEmpty(histories)) {
item.setMyStatus(getMyStatus(histories, userHistory));
} else {
//不存在评审历史
item.setMyStatus(FunctionalCaseReviewStatus.UNDER_REVIEWED.name());
}
}
}); });
} }
return list; return list;
} }
private String getMyStatus(List<CaseReviewHistory> histories, List<CaseReviewHistory> userHistory) {
if (CollectionUtils.isNotEmpty(userHistory)) {
//当前用户存在评审记录
return userHistory.get(0).getStatus();
}
//重新提审记录
List<CaseReviewHistory> reReviewed = histories.stream().filter(history -> StringUtils.equalsIgnoreCase(history.getStatus(), FunctionalCaseReviewStatus.RE_REVIEWED.name())).toList();
if (CollectionUtils.isNotEmpty(reReviewed)) {
return FunctionalCaseReviewStatus.RE_REVIEWED.name();
}
return FunctionalCaseReviewStatus.UN_REVIEWED.name();
}
/** /**
* 批量删除 * 批量删除
* *

View File

@ -97,9 +97,18 @@ public class CaseReviewFunctionalCaseControllerTests extends BaseTest {
@Sql(scripts = {"/dml/init_review_functional_case_test.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED)) @Sql(scripts = {"/dml/init_review_functional_case_test.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void testReviewCasePage() throws Exception { public void testReviewCasePage() throws Exception {
ReviewFunctionalCasePageRequest request = new ReviewFunctionalCasePageRequest(); ReviewFunctionalCasePageRequest request = new ReviewFunctionalCasePageRequest();
request.setReviewId("wx_review_id_1");
request.setCurrent(1); request.setCurrent(1);
request.setPageSize(10); request.setPageSize(10);
request.setProjectId("wx_test_project");
request.setReviewId("wx_review_id_5");
request.setViewFlag(true);
request.setViewStatusFlag(true);
this.requestPostWithOkAndReturn(REVIEW_CASE_PAGE, request);
request.setReviewId("wx_review_id_1");
this.requestPostWithOkAndReturn(REVIEW_CASE_PAGE, request);
request.setReviewId("wx_review_id_1");
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("customs", Arrays.asList(new LinkedHashMap() {{ map.put("customs", Arrays.asList(new LinkedHashMap() {{
put("id", "TEST_FIELD_ID"); put("id", "TEST_FIELD_ID");
@ -109,10 +118,11 @@ public class CaseReviewFunctionalCaseControllerTests extends BaseTest {
}})); }}));
request.setCombine(map); request.setCombine(map);
request.setViewFlag(true); request.setViewFlag(true);
request.setProjectId("wx_test_project"); request.setViewStatusFlag(true);
this.requestPostWithOkAndReturn(REVIEW_CASE_PAGE, request); this.requestPostWithOkAndReturn(REVIEW_CASE_PAGE, request);
this.requestPostWithOkAndReturn(REVIEW_FUNCTIONAL_CASE_MODULE_COUNT, request); this.requestPostWithOkAndReturn(REVIEW_FUNCTIONAL_CASE_MODULE_COUNT, request);
request.setViewFlag(false); request.setViewFlag(false);
request.setViewStatusFlag(false);
this.requestPostWithOkAndReturn(REVIEW_CASE_PAGE, request); this.requestPostWithOkAndReturn(REVIEW_CASE_PAGE, request);
request.setSort(new HashMap<>() {{ request.setSort(new HashMap<>() {{
@ -374,7 +384,6 @@ public class CaseReviewFunctionalCaseControllerTests extends BaseTest {
this.requestPostWithOk(REVIEW_FUNCTIONAL_CASE_BATCH_REVIEW, request); this.requestPostWithOk(REVIEW_FUNCTIONAL_CASE_BATCH_REVIEW, request);
request = new BatchReviewFunctionalCaseRequest(); request = new BatchReviewFunctionalCaseRequest();
request.setReviewId("wx_review_id_1"); request.setReviewId("wx_review_id_1");
request.setReviewPassRule(CaseReviewPassRule.MULTIPLE.toString()); request.setReviewPassRule(CaseReviewPassRule.MULTIPLE.toString());

View File

@ -132,7 +132,9 @@ VALUES ('wx_history', 'wx_review_id_3', 'wx_case_id_1', NULL, 'PASS', b'0', b'0'
('wx_history_4', 'wx_review_id_4', 'wx_case_id_1', NULL, 'PASS', b'0', b'0', NULL, 'admin', 1669174143999), ('wx_history_4', 'wx_review_id_4', 'wx_case_id_1', NULL, 'PASS', b'0', b'0', NULL, 'admin', 1669174143999),
('wx_history_5', 'wx_review_id_4', 'wx_case_id_2', NULL, 'UN_PASS', b'0', b'0', NULL, 'admin', 1669174143999), ('wx_history_5', 'wx_review_id_4', 'wx_case_id_2', NULL, 'UN_PASS', b'0', b'0', NULL, 'admin', 1669174143999),
('wx_history_6', 'wx_review_id_1', 'gyq_case_id_5', NULL, 'PASS', b'0', b'0', NULL, 'gyq_case_review', 1669174143999), ('wx_history_6', 'wx_review_id_1', 'gyq_case_id_5', NULL, 'PASS', b'0', b'0', NULL, 'gyq_case_review', 1669174143999),
('wx_history_7', 'wx_review_id_1', 'gyq_case_id_5', NULL, 'UN_PASS', b'0', b'0', NULL, 'GGG', 1669174143999); ('wx_history_7', 'wx_review_id_1', 'gyq_case_id_5', NULL, 'UN_PASS', b'0', b'0', NULL, 'GGG', 1669174143999),
('wx_history_8', 'wx_review_id_1', 'wx_case_id_1', NULL, 'UN_PASS', b'0', b'0', NULL, 'admin', 1669174143999),
('wx_history_9', 'wx_review_id_5', 'gyq_case_id_d', NULL, 'RE_REVIEWED', b'0', b'0', NULL, 'GGG', 1669174143999);
INSERT INTO case_review_user(review_id, user_id) INSERT INTO case_review_user(review_id, user_id)
VALUES ('wx_review_id_4', 'admin') VALUES ('wx_review_id_4', 'admin')

View File

@ -117,6 +117,7 @@ export interface ReviewListQueryParams extends TableQueryParams {
export interface ReviewDetailCaseListQueryParams extends TableQueryParams { export interface ReviewDetailCaseListQueryParams extends TableQueryParams {
viewFlag: boolean; // 是否只看我的 viewFlag: boolean; // 是否只看我的
reviewId: string; reviewId: string;
viewStatusFlag: boolean; // 我的评审状态
} }
// 评审详情-用例拖拽排序入参 // 评审详情-用例拖拽排序入参
export interface SortReviewCaseParams { export interface SortReviewCaseParams {

View File

@ -16,9 +16,9 @@
: t('caseManagement.caseReview.multi') : t('caseManagement.caseReview.multi')
}} }}
</div> </div>
<div class="ml-[16px] flex items-center"> <div v-show="reviewDetail.reviewPassRule === 'MULTIPLE'" class="ml-[16px] flex items-center">
<a-switch v-model:model-value="onlyMine" size="small" class="mr-[8px]" type="line" /> <a-switch v-model:model-value="onlyMineStatus" size="small" class="mr-[8px]" type="line" />
{{ t('caseManagement.caseReview.myReview') }} {{ t('caseManagement.caseReview.myReviewStatus') }}
</div> </div>
</template> </template>
<div class="flex h-full w-full border-t border-[var(--color-text-n8)]"> <div class="flex h-full w-full border-t border-[var(--color-text-n8)]">
@ -323,7 +323,8 @@
{ label: t(reviewResultMap.RE_REVIEWED.label), value: 'RE_REVIEWED' }, { label: t(reviewResultMap.RE_REVIEWED.label), value: 'RE_REVIEWED' },
]); ]);
const onlyMine = ref(false); const viewFlag = ref(false);
const onlyMineStatus = ref(false);
const keyword = ref(''); const keyword = ref('');
const caseList = ref<ReviewCaseItem[]>([]); const caseList = ref<ReviewCaseItem[]>([]);
const pageNation = ref({ const pageNation = ref({
@ -341,7 +342,8 @@
const res = await getReviewDetailCasePage({ const res = await getReviewDetailCasePage({
projectId: appStore.currentProjectId, projectId: appStore.currentProjectId,
reviewId: reviewId.value, reviewId: reviewId.value,
viewFlag: onlyMine.value, viewFlag: viewFlag.value,
viewStatusFlag: onlyMineStatus.value,
keyword: keyword.value, keyword: keyword.value,
current: pageNation.value.current || 1, current: pageNation.value.current || 1,
pageSize: pageNation.value.pageSize, pageSize: pageNation.value.pageSize,
@ -363,7 +365,7 @@
} }
watch( watch(
() => onlyMine.value, () => onlyMineStatus.value,
() => { () => {
pageNation.value.current = 1; pageNation.value.current = 1;
loadCaseList(); loadCaseList();
@ -566,7 +568,7 @@
total, total,
pageSize, pageSize,
current, current,
onlyMine: _onlyMine, viewFlag: _onlyMine,
keyword: _keyword, keyword: _keyword,
combine, combine,
sort, sort,
@ -578,7 +580,7 @@
pageSize, pageSize,
current, current,
}; };
onlyMine.value = !!_onlyMine; viewFlag.value = !!_onlyMine;
keyword.value = _keyword; keyword.value = _keyword;
otherListQueryParams.value = { otherListQueryParams.value = {
combine, combine,

View File

@ -111,7 +111,7 @@ export default {
'caseManagement.caseReview.append': 'Append', 'caseManagement.caseReview.append': 'Append',
'caseManagement.caseReview.appendTip1': 'Open: Add reviewer', 'caseManagement.caseReview.appendTip1': 'Open: Add reviewer',
'caseManagement.caseReview.appendTip2': 'Close: Update reviewers', 'caseManagement.caseReview.appendTip2': 'Close: Update reviewers',
'caseManagement.caseReview.myReview': 'My reviews', 'caseManagement.caseReview.myReviewStatus': 'My reviews status',
'caseManagement.caseReview.caseLevel': 'Case level', 'caseManagement.caseReview.caseLevel': 'Case level',
'caseManagement.caseReview.caseVersion': 'Case version', 'caseManagement.caseReview.caseVersion': 'Case version',
'caseManagement.caseReview.caseStatus': 'Case status', 'caseManagement.caseReview.caseStatus': 'Case status',

View File

@ -101,7 +101,7 @@ export default {
'caseManagement.caseReview.append': '追加', 'caseManagement.caseReview.append': '追加',
'caseManagement.caseReview.appendTip1': '开启:新增评审人', 'caseManagement.caseReview.appendTip1': '开启:新增评审人',
'caseManagement.caseReview.appendTip2': '关闭:更新评审人', 'caseManagement.caseReview.appendTip2': '关闭:更新评审人',
'caseManagement.caseReview.myReview': '我的评审', 'caseManagement.caseReview.myReviewStatus': '我的评审状态',
'caseManagement.caseReview.caseLevel': '用例等级', 'caseManagement.caseReview.caseLevel': '用例等级',
'caseManagement.caseReview.caseVersion': '用例版本', 'caseManagement.caseReview.caseVersion': '用例版本',
'caseManagement.caseReview.caseStatus': '用例状态', 'caseManagement.caseReview.caseStatus': '用例状态',