diff --git a/backend/app/src/main/java/io/metersphere/listener/AppStartListener.java b/backend/app/src/main/java/io/metersphere/listener/AppStartListener.java index be13ca21dc..b7cd619148 100644 --- a/backend/app/src/main/java/io/metersphere/listener/AppStartListener.java +++ b/backend/app/src/main/java/io/metersphere/listener/AppStartListener.java @@ -1,6 +1,8 @@ package io.metersphere.listener; import io.metersphere.api.event.ApiEventSource; +import io.metersphere.functional.event.CaseEventSource; +import io.metersphere.functional.listener.CaseEventListener; import io.metersphere.plan.listener.ExecEventListener; import io.metersphere.sdk.constants.StorageType; import io.metersphere.sdk.file.FileCenter; @@ -31,22 +33,25 @@ public class AppStartListener implements ApplicationRunner { // 注册所有监听源 LogUtils.info("初始化接口事件源"); ApiEventSource apiEventSource = CommonBeanFactory.getBean(ApiEventSource.class); + LogUtils.info("初始化用例管理事件源"); + CaseEventSource caseEventSource = CommonBeanFactory.getBean(CaseEventSource.class); LogUtils.info("初始化性能测试事件源"); //LoadEventSource loadEventSource = CommonBeanFactory.getBean(LoadEventSource.class); //todo: 注册其他事件源 - // 创建监听器对象并注册到多个事件源 ExecEventListener listener = CommonBeanFactory.getBean(ExecEventListener.class); apiEventSource.addListener(listener); //todo: 注册其他监听器 + CaseEventListener caseEventListener = CommonBeanFactory.getBean(CaseEventListener.class); + caseEventSource.addListener(caseEventListener); //loadEventSource.addListener(listener); // 触发事件 apiEventSource.fireEvent("API", "Event after removing the listener test."); //loadEventSource.fireEvent("LOAD","Event after removing the listener."); - + caseEventSource.fireEvent("CASE", "Event after removing the listener test."); // 加载插件 pluginLoadService.loadPlugins(); } diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/listener/Event.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/listener/Event.java index c6d934ffb6..924ca9bb0f 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/listener/Event.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/listener/Event.java @@ -1,5 +1,36 @@ package io.metersphere.sdk.listener; -public record Event(String module, String message) { +import lombok.Data; +import java.util.Map; + +@Data +public class Event { + private String module; + private String message; + private Map paramMap; + + public Event(String module, String message) { + this.module = module; + this.message = message; + } + + public Event(String module, String message, Map paramMap) { + this.module = module; + this.message = message; + this.paramMap = paramMap; + } + + + public String module() { + return this.module; + } + + public String message() { + return this.message; + } + + public Map paramMap() { + return this.paramMap; + } } diff --git a/backend/framework/sdk/src/main/java/io/metersphere/sdk/listener/EventSource.java b/backend/framework/sdk/src/main/java/io/metersphere/sdk/listener/EventSource.java index b40cd26aba..ba157e064c 100644 --- a/backend/framework/sdk/src/main/java/io/metersphere/sdk/listener/EventSource.java +++ b/backend/framework/sdk/src/main/java/io/metersphere/sdk/listener/EventSource.java @@ -1,5 +1,7 @@ package io.metersphere.sdk.listener; +import java.util.Map; + public interface EventSource { /** * 注册监听 @@ -10,4 +12,9 @@ public interface EventSource { * 触发事件 */ void fireEvent(String module, String message); + + /** + * 触发事件,带有参数 + */ + void fireEvent(String module, String message, Map paramMap); } diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/event/ApiEventSource.java b/backend/services/api-test/src/main/java/io/metersphere/api/event/ApiEventSource.java index e8d71ae76d..5da0649518 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/event/ApiEventSource.java +++ b/backend/services/api-test/src/main/java/io/metersphere/api/event/ApiEventSource.java @@ -3,8 +3,11 @@ package io.metersphere.api.event; import io.metersphere.sdk.listener.Event; import io.metersphere.sdk.listener.EventListener; import io.metersphere.sdk.listener.EventSource; +import io.metersphere.sdk.util.LogUtils; import org.springframework.stereotype.Component; +import java.util.Map; + @Component public class ApiEventSource implements EventSource { private EventListener listener; @@ -19,4 +22,12 @@ public class ApiEventSource implements EventSource { Event event = new Event("API", message); listener.onEvent(event); } + + @Override + public void fireEvent(String module, String message, Map paramMap) { + Event event = new Event("API", message, paramMap); + listener.onEvent(event); + LogUtils.info("带有参数的监听事件"); + } + } diff --git a/backend/services/api-test/src/test/java/io/metersphere/api/controller/EventSourceTests.java b/backend/services/api-test/src/test/java/io/metersphere/api/controller/EventSourceTests.java index 1c69a2b301..dc14ddf855 100644 --- a/backend/services/api-test/src/test/java/io/metersphere/api/controller/EventSourceTests.java +++ b/backend/services/api-test/src/test/java/io/metersphere/api/controller/EventSourceTests.java @@ -12,6 +12,8 @@ import org.junit.jupiter.api.TestMethodOrder; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import java.util.HashMap; + @SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) @@ -33,5 +35,7 @@ public class EventSourceTests { }); // 触发事件 apiEventSource.fireEvent("API", "Event after removing the listener test."); + // 触发事件待参数 + apiEventSource.fireEvent("API", "Event after removing the listener test.",new HashMap<>()); } } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/constants/CaseEvent.java b/backend/services/case-management/src/main/java/io/metersphere/functional/constants/CaseEvent.java new file mode 100644 index 0000000000..9ac616b72a --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/constants/CaseEvent.java @@ -0,0 +1,22 @@ +package io.metersphere.functional.constants; + +public interface CaseEvent { + + interface Event { + String ASSOCIATE = "associate"; + String DISASSOCIATE = "disassociate"; + String BATCH_DISASSOCIATE = "batchDisassociate"; + String DELETE_FUNCTIONAL_CASE = "deleteFunctionalCase"; + String DELETE_TRASH_FUNCTIONAL_CASE = "deleteTrashFunctionalCase"; + String RECOVER_FUNCTIONAL_CASE = "recoverFunctionalCase"; + } + + interface Param { + String REVIEW_ID = "reviewId"; + String CASE_IDS = "caseIds"; + String PASS_COUNT = "passCount"; + String CASE_COUNT = "caseCount"; + + } + +} diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/event/CaseEventSource.java b/backend/services/case-management/src/main/java/io/metersphere/functional/event/CaseEventSource.java new file mode 100644 index 0000000000..10a9d212fb --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/event/CaseEventSource.java @@ -0,0 +1,32 @@ +package io.metersphere.functional.event; + +import io.metersphere.sdk.listener.Event; +import io.metersphere.sdk.listener.EventListener; +import io.metersphere.sdk.listener.EventSource; +import io.metersphere.sdk.util.LogUtils; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +public class CaseEventSource implements EventSource { + private EventListener listener; + + @Override + public void addListener(EventListener listener) { + this.listener = listener; + } + + @Override + public void fireEvent(String module, String message) { + Event event = new Event("CASE", message); + listener.onEvent(event); + } + + @Override + public void fireEvent(String module, String message, Map paramMap) { + Event event = new Event("CASE", message, paramMap); + listener.onEvent(event); + LogUtils.info("带有参数的监听事件"); + } +} diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/listener/CaseEventListener.java b/backend/services/case-management/src/main/java/io/metersphere/functional/listener/CaseEventListener.java new file mode 100644 index 0000000000..b2d1ac918a --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/listener/CaseEventListener.java @@ -0,0 +1,201 @@ +package io.metersphere.functional.listener; + +import io.metersphere.functional.constants.CaseEvent; +import io.metersphere.functional.constants.FunctionalCaseReviewStatus; +import io.metersphere.functional.domain.CaseReview; +import io.metersphere.functional.domain.CaseReviewFunctionalCase; +import io.metersphere.functional.domain.CaseReviewFunctionalCaseExample; +import io.metersphere.functional.domain.CaseReviewFunctionalCaseUserExample; +import io.metersphere.functional.mapper.CaseReviewFunctionalCaseMapper; +import io.metersphere.functional.mapper.CaseReviewFunctionalCaseUserMapper; +import io.metersphere.functional.mapper.CaseReviewMapper; +import io.metersphere.sdk.listener.Event; +import io.metersphere.sdk.listener.EventListener; +import io.metersphere.sdk.util.JSON; +import io.metersphere.sdk.util.LogUtils; +import jakarta.annotation.Resource; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +public class CaseEventListener implements EventListener { + @Resource + private CaseReviewMapper caseReviewMapper; + @Resource + private CaseReviewFunctionalCaseUserMapper caseReviewFunctionalCaseUserMapper; + @Resource + private CaseReviewFunctionalCaseMapper caseReviewFunctionalCaseMapper; + + @Async + @Override + public void onEvent(Event event) { + LogUtils.info("CaseEventListener: " + event.module() + ":" + event.message()); + //批量修改用例评审人 + //重新提审(批量)/自动重新提审(编辑) + //批量修改结果 + String message = event.message(); + switch (message) { + case CaseEvent.Event.ASSOCIATE -> { + updateCaseReviewByAssociate(event); + } + case CaseEvent.Event.DISASSOCIATE -> { + updateCaseReviewByDisAssociate(event); + } + case CaseEvent.Event.BATCH_DISASSOCIATE -> { + updateCaseReviewByBatchDisassociate(event); + } + case CaseEvent.Event.DELETE_FUNCTIONAL_CASE -> { + updateCaseReviewByDeleteFunctionalCase(event); + } + case CaseEvent.Event.DELETE_TRASH_FUNCTIONAL_CASE -> { + updateCaseReviewByDeleteTrashFunctionalCase(event); + } + case CaseEvent.Event.RECOVER_FUNCTIONAL_CASE -> { + updateCaseReviewByRecoverFunctionalCase(event); + } + default -> LogUtils.info("CaseEventListener: " + event.module() + ":" + event.message()); + } + + } + + /** + * 功能用例的回收站恢复/批量恢复重新计算用例评审的通过率和用例数 + */ + private void updateCaseReviewByRecoverFunctionalCase(Event event) { + List caseReviewFunctionalCases = getCaseReviewFunctionalCases(event); + Map> reviewIdMap = caseReviewFunctionalCases.stream().collect(Collectors.groupingBy(CaseReviewFunctionalCase::getReviewId)); + reviewIdMap.forEach((reviewId, caseReviewFunctionalCaseList) -> { + CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(reviewId); + List passList = caseReviewFunctionalCases.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getStatus(), FunctionalCaseReviewStatus.PASS.toString())).toList(); + updateCaseReview(reviewId, caseReview.getCaseCount() + caseReviewFunctionalCaseList.size(), passList.size()); + }); + } + + /** + * 功能用例的回收站删除/批量删除重新计算用例评审的通过率和用例数 + */ + private void updateCaseReviewByDeleteTrashFunctionalCase(Event event) { + List caseReviewFunctionalCases = getCaseReviewFunctionalCases(event); + if (CollectionUtils.isEmpty(caseReviewFunctionalCases)) { + return; + } + Map> reviewIdMap = caseReviewFunctionalCases.stream().collect(Collectors.groupingBy(CaseReviewFunctionalCase::getReviewId)); + reviewIdMap.forEach((reviewId, caseReviewFunctionalCaseList) -> { + CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(reviewId); + List passList = caseReviewFunctionalCases.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getStatus(), FunctionalCaseReviewStatus.PASS.toString())).toList(); + updateCaseReview(reviewId, caseReview.getCaseCount() - caseReviewFunctionalCaseList.size(), passList.size()); + }); + + } + + /** + * 功能用例的删除/批量删除重新计算用例评审的通过率和用例数 + */ + private void updateCaseReviewByDeleteFunctionalCase(Event event) { + List caseReviewFunctionalCases = getCaseReviewFunctionalCases(event); + if (CollectionUtils.isEmpty(caseReviewFunctionalCases)) { + return; + } + Map> reviewIdMap = caseReviewFunctionalCases.stream().collect(Collectors.groupingBy(CaseReviewFunctionalCase::getReviewId)); + reviewIdMap.forEach((reviewId, caseReviewFunctionalCaseList) -> { + CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(reviewId); + List passList = caseReviewFunctionalCases.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getStatus(), FunctionalCaseReviewStatus.PASS.toString())).toList(); + updateCaseReview(reviewId, caseReview.getCaseCount() - caseReviewFunctionalCaseList.size(), passList.size()); + List caseIdList = caseReviewFunctionalCaseList.stream().map(CaseReviewFunctionalCase::getId).toList(); + deleteReviewFunctionalCaseUser(caseIdList, reviewId); + }); + + } + + private List getCaseReviewFunctionalCases(Event event) { + Map paramMap = event.paramMap(); + Object caseIds = paramMap.get(CaseEvent.Param.CASE_IDS); + List caseIdList = JSON.parseArray(JSON.toJSONString(caseIds), String.class); + CaseReviewFunctionalCaseExample functionalCaseExample = new CaseReviewFunctionalCaseExample(); + functionalCaseExample.createCriteria().andCaseIdIn(caseIdList); + return caseReviewFunctionalCaseMapper.selectByExample(functionalCaseExample); + } + + /** + * 1.批量取消关联重新计算用例评审的通过率和用例数 + * 2.删除用例和用例评审人的关系 + */ + private void updateCaseReviewByBatchDisassociate(Event event) { + Map paramMap = event.paramMap(); + String reviewId = paramMap.get(CaseEvent.Param.REVIEW_ID).toString(); + CaseReview caseReview = caseReviewMapper.selectByPrimaryKey(reviewId); + Integer oldCaseCount = caseReview.getCaseCount(); + Object caseIds = paramMap.get(CaseEvent.Param.CASE_IDS); + List caseIdList = JSON.parseArray(JSON.toJSONString(caseIds), String.class); + int passNumber = Integer.parseInt(paramMap.get(CaseEvent.Param.PASS_COUNT).toString()); + updateCaseReview(reviewId, oldCaseCount - caseIdList.size(), passNumber); + //删除用例和用例评审人的关系 + deleteCaseReviewFunctionalCaseUser(event); + } + + /** + * 1.单独取消关联重新计算用例评审的通过率和用例数 + * 2.删除用例和用例评审人的关系 + */ + private void updateCaseReviewByDisAssociate(Event event) { + updateCaseReviewByAssociate(event); + //删除用例和用例评审人的关系 + deleteCaseReviewFunctionalCaseUser(event); + } + + /** + * 删除用例和用例评审人的关系 + */ + private void deleteCaseReviewFunctionalCaseUser(Event event) { + Map paramMap = event.paramMap(); + Object caseIds = paramMap.get(CaseEvent.Param.CASE_IDS); + List caseIdList = JSON.parseArray(JSON.toJSONString(caseIds), String.class); + String reviewId = paramMap.get(CaseEvent.Param.REVIEW_ID).toString(); + deleteReviewFunctionalCaseUser(caseIdList, reviewId); + } + + private void deleteReviewFunctionalCaseUser(List caseIdList, String reviewId) { + CaseReviewFunctionalCaseUserExample caseReviewFunctionalCaseUserExample = new CaseReviewFunctionalCaseUserExample(); + caseReviewFunctionalCaseUserExample.createCriteria().andCaseIdIn(caseIdList).andReviewIdEqualTo(reviewId); + caseReviewFunctionalCaseUserMapper.deleteByExample(caseReviewFunctionalCaseUserExample); + } + + /** + * 关联用例(单独/批量)重新计算用例评审的通过率和用例数 + */ + private void updateCaseReviewByAssociate(Event event) { + Map paramMap = event.paramMap(); + String reviewId = paramMap.get(CaseEvent.Param.REVIEW_ID).toString(); + int caseCount = Integer.parseInt(paramMap.get(CaseEvent.Param.CASE_COUNT).toString()); + int passNumber = Integer.parseInt(paramMap.get(CaseEvent.Param.PASS_COUNT).toString()); + updateCaseReview(reviewId, caseCount, passNumber); + } + + /** + * 重新计算用例评审的通过率和用例数 + */ + private void updateCaseReview(String reviewId, int caseCount, int passNumber) { + CaseReview caseReview = new CaseReview(); + caseReview.setId(reviewId); + //更新用例数量 + caseReview.setCaseCount(caseCount); + //通过率 + BigDecimal passCount = BigDecimal.valueOf(passNumber); + BigDecimal totalCount = BigDecimal.valueOf(caseReview.getCaseCount()); + if (totalCount.compareTo(BigDecimal.ZERO) == 0) { + caseReview.setPassRate(BigDecimal.ZERO); + } else { + BigDecimal passRate = passCount.divide(totalCount, 2, RoundingMode.HALF_UP); + caseReview.setPassRate(passRate); + } + caseReviewMapper.updateByPrimaryKeySelective(caseReview); + } +} diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewFunctionalCaseMapper.java b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewFunctionalCaseMapper.java index 4811bb5e3e..a3b64f662e 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewFunctionalCaseMapper.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewFunctionalCaseMapper.java @@ -1,5 +1,6 @@ package io.metersphere.functional.mapper; +import io.metersphere.functional.domain.CaseReviewFunctionalCase; import io.metersphere.functional.dto.FunctionalCaseReviewDTO; import io.metersphere.functional.dto.ReviewFunctionalCaseDTO; import io.metersphere.functional.request.BaseReviewCaseBatchRequest; @@ -27,4 +28,6 @@ public interface ExtCaseReviewFunctionalCaseMapper { Long getPos(@Param("reviewId") String reviewId); List getIds(@Param("request") BaseReviewCaseBatchRequest request, @Param("userId") String userId, @Param("deleted") boolean deleted); + + List getList(@Param("reviewId") String reviewId, @Param("reviewIds") List reviewIds, @Param("deleted") boolean deleted); } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewFunctionalCaseMapper.xml b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewFunctionalCaseMapper.xml index 5087e04140..6910561c47 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewFunctionalCaseMapper.xml +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/mapper/ExtCaseReviewFunctionalCaseMapper.xml @@ -286,4 +286,23 @@ LIMIT 1; + + \ No newline at end of file diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewFunctionalCaseService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewFunctionalCaseService.java index 99a042525d..a8467fedb6 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewFunctionalCaseService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewFunctionalCaseService.java @@ -1,6 +1,7 @@ package io.metersphere.functional.service; +import io.metersphere.functional.constants.CaseEvent; import io.metersphere.functional.constants.FunctionalCaseReviewStatus; import io.metersphere.functional.domain.CaseReviewFunctionalCase; import io.metersphere.functional.domain.CaseReviewFunctionalCaseExample; @@ -12,18 +13,18 @@ import io.metersphere.functional.mapper.ExtCaseReviewFunctionalCaseUserMapper; import io.metersphere.functional.mapper.ExtFunctionalCaseModuleMapper; import io.metersphere.functional.request.BaseReviewCaseBatchRequest; import io.metersphere.functional.request.ReviewFunctionalCasePageRequest; +import io.metersphere.functional.utils.CaseListenerUtils; import io.metersphere.project.domain.ProjectVersion; import io.metersphere.project.mapper.ExtBaseProjectVersionMapper; import io.metersphere.system.dto.sdk.BaseTreeNode; import io.metersphere.system.uid.IDGenerator; import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -89,8 +90,8 @@ public class CaseReviewFunctionalCaseService { list.forEach(item -> { item.setModuleName(moduleMap.get(item.getModuleId())); item.setVersionName(versionMap.get(item.getVersionId())); - item.setReviewers(Arrays.asList(userIdMap.get(item.getId()))); - item.setReviewNames(Arrays.asList(userNameMap.get(item.getId()))); + item.setReviewers(Collections.singletonList(userIdMap.get(item.getId()))); + item.setReviewNames(Collections.singletonList(userNameMap.get(item.getId()))); }); } return list; @@ -106,10 +107,23 @@ public class CaseReviewFunctionalCaseService { if (CollectionUtils.isNotEmpty(ids)) { CaseReviewFunctionalCaseExample example = new CaseReviewFunctionalCaseExample(); example.createCriteria().andIdIn(ids); + Map param = getParam(request.getReviewId(), example, ids); + CaseListenerUtils.addListener(param, CaseEvent.Event.BATCH_DISASSOCIATE); caseReviewFunctionalCaseMapper.deleteByExample(example); } } + private Map getParam(String reviewId, CaseReviewFunctionalCaseExample example, List ids) { + List caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(example); + List caseIds = caseReviewFunctionalCases.stream().map(CaseReviewFunctionalCase::getCaseId).toList(); + List passList = caseReviewFunctionalCases.stream().filter(t -> !ids.contains(t.getId()) && StringUtils.equalsIgnoreCase(t.getStatus(), FunctionalCaseReviewStatus.PASS.toString())).toList(); + Map param = new HashMap<>(); + param.put(CaseEvent.Param.CASE_IDS,caseIds); + param.put(CaseEvent.Param.REVIEW_ID, reviewId); + param.put(CaseEvent.Param.PASS_COUNT,passList.size()); + return param; + } + public List doSelectIds(BaseReviewCaseBatchRequest request) { if (request.isSelectAll()) { List ids = extCaseReviewFunctionalCaseMapper.getIds(request, request.getUserId(), false); @@ -126,9 +140,9 @@ public class CaseReviewFunctionalCaseService { /** * 评审详情页面 创建用例并关联 * - * @param caseId - * @param userId - * @param reviewId + * @param caseId 功能用例ID + * @param userId 当前操作人 + * @param reviewId 评审id */ public void addCaseReviewFunctionalCase(String caseId, String userId, String reviewId) { CaseReviewFunctionalCase reviewFunctionalCase = new CaseReviewFunctionalCase(); diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java index 9e192f4525..c33c23022c 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/CaseReviewService.java @@ -1,6 +1,7 @@ package io.metersphere.functional.service; +import io.metersphere.functional.constants.CaseEvent; import io.metersphere.functional.constants.CaseReviewStatus; import io.metersphere.functional.constants.FunctionalCaseReviewStatus; import io.metersphere.functional.domain.*; @@ -10,6 +11,7 @@ import io.metersphere.functional.dto.CaseReviewUserDTO; import io.metersphere.functional.mapper.*; import io.metersphere.functional.request.*; import io.metersphere.functional.result.CaseManagementResultCode; +import io.metersphere.functional.utils.CaseListenerUtils; import io.metersphere.project.dto.ModuleCountDTO; import io.metersphere.sdk.constants.ApplicationNumScope; import io.metersphere.sdk.constants.PermissionConstants; @@ -33,8 +35,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; -import java.math.RoundingMode; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -71,8 +73,6 @@ public class CaseReviewService { @Resource private DeleteCaseReviewService deleteCaseReviewService; @Resource - private CaseReviewFunctionalCaseUserMapper caseReviewFunctionalCaseUserMapper; - @Resource private ExtCaseReviewFunctionalCaseMapper extCaseReviewFunctionalCaseMapper; @Resource private CaseReviewModuleService caseReviewModuleService; @@ -187,9 +187,7 @@ public class CaseReviewService { * @return Map */ private Map> getReviewCaseMap(List reviewIds) { - CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample(); - caseReviewFunctionalCaseExample.createCriteria().andReviewIdIn(reviewIds); - List caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample); + List caseReviewFunctionalCases = extCaseReviewFunctionalCaseMapper.getList(null, reviewIds, false); return caseReviewFunctionalCases.stream().collect(Collectors.groupingBy(CaseReviewFunctionalCase::getReviewId)); } @@ -450,9 +448,7 @@ public class CaseReviewService { if (CollectionUtils.isEmpty(functionalCases)) { return; } - CaseReviewFunctionalCaseExample caseReviewFunctionalCaseExample = new CaseReviewFunctionalCaseExample(); - caseReviewFunctionalCaseExample.createCriteria().andReviewIdEqualTo(caseReviewId); - List caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample); + List caseReviewFunctionalCases = extCaseReviewFunctionalCaseMapper.getList(caseReviewId, null, false); List castIds = caseReviewFunctionalCases.stream().map(CaseReviewFunctionalCase::getCaseId).toList(); List caseRealIds = caseIds.stream().filter(t -> !castIds.contains(t)).toList(); SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); @@ -467,19 +463,20 @@ public class CaseReviewService { } finally { SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory); } - List passList = caseReviewFunctionalCases.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getStatus(), FunctionalCaseReviewStatus.PASS.toString())).toList(); - CaseReview caseReview = new CaseReview(); - caseReview.setId(caseReviewId); - //更新用例数量 - caseReview.setCaseCount(caseReviewExist.getCaseCount() + caseRealIds.size()); - //通过率 - BigDecimal passCount = BigDecimal.valueOf(passList.size()); - BigDecimal totalCount = BigDecimal.valueOf(caseReview.getCaseCount()); - BigDecimal passRate = passCount.divide(totalCount, 2, RoundingMode.HALF_UP); - caseReview.setPassRate(passRate); - caseReviewMapper.updateByPrimaryKeySelective(caseReview); + Map param = getParam(caseReviewFunctionalCases, caseReviewExist.getCaseCount() + caseRealIds.size(), caseReviewId); + CaseListenerUtils.addListener(param, CaseEvent.Event.ASSOCIATE); } + private Map getParam(List caseReviewFunctionalCases, int caseReviewExist, String caseReviewId) { + List passList = caseReviewFunctionalCases.stream().filter(t -> StringUtils.equalsIgnoreCase(t.getStatus(), FunctionalCaseReviewStatus.PASS.toString())).toList(); + Map param = new HashMap<>(); + param.put(CaseEvent.Param.CASE_COUNT, caseReviewExist); + param.put(CaseEvent.Param.REVIEW_ID, caseReviewId); + param.put(CaseEvent.Param.PASS_COUNT, passList.size()); + return param; + } + + public List doSelectIds(T dto, String projectId) { BaseFunctionalCaseBatchDTO request = (BaseFunctionalCaseBatchDTO) dto; if (request.isSelectAll()) { @@ -565,30 +562,11 @@ public class CaseReviewService { 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 caseReviewFunctionalCases = caseReviewFunctionalCaseMapper.selectByExample(caseReviewFunctionalCaseExample); - List 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); + List caseReviewFunctionalCases = extCaseReviewFunctionalCaseMapper.getList(reviewId, null, false); + Map param = getParam(caseReviewFunctionalCases, caseReviewFunctionalCases.size(), reviewId); + param.put(CaseEvent.Param.CASE_IDS, List.of(caseId)); + CaseListenerUtils.addListener(param, CaseEvent.Event.DISASSOCIATE); } public Map moduleCount(CaseReviewPageRequest request) { diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseService.java index c64c09dcf6..c32683a55f 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseService.java @@ -1,5 +1,6 @@ package io.metersphere.functional.service; +import io.metersphere.functional.constants.CaseEvent; import io.metersphere.functional.constants.FunctionalCaseReviewStatus; import io.metersphere.functional.domain.*; import io.metersphere.functional.dto.*; @@ -9,6 +10,7 @@ import io.metersphere.functional.mapper.FunctionalCaseFollowerMapper; import io.metersphere.functional.mapper.FunctionalCaseMapper; import io.metersphere.functional.request.*; import io.metersphere.functional.result.CaseManagementResultCode; +import io.metersphere.functional.utils.CaseListenerUtils; import io.metersphere.project.domain.FileAssociation; import io.metersphere.project.dto.ModuleCountDTO; import io.metersphere.project.mapper.ExtBaseProjectVersionMapper; @@ -372,13 +374,21 @@ public class FunctionalCaseService { } private void handDeleteFunctionalCase(List ids, Boolean deleteAll, String userId) { + Map param = new HashMap<>(); if (deleteAll) { //全部删除 进入回收站 List refId = extFunctionalCaseMapper.getRefIds(ids, false); + FunctionalCaseExample functionalCaseExample = new FunctionalCaseExample(); + functionalCaseExample.createCriteria().andRefIdIn(refId); + List functionalCases = functionalCaseMapper.selectByExample(functionalCaseExample); + List caseIds = functionalCases.stream().map(FunctionalCase::getId).toList(); + param.put(CaseEvent.Param.CASE_IDS, caseIds); extFunctionalCaseMapper.batchDelete(refId, userId); } else { + param.put(CaseEvent.Param.CASE_IDS, ids); doDelete(ids, userId); } + CaseListenerUtils.addListener(param, CaseEvent.Event.DELETE_FUNCTIONAL_CASE); } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseTrashService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseTrashService.java index ddf84b12d6..32ae498b49 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseTrashService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseTrashService.java @@ -1,5 +1,6 @@ package io.metersphere.functional.service; +import io.metersphere.functional.constants.CaseEvent; import io.metersphere.functional.domain.FunctionalCase; import io.metersphere.functional.domain.FunctionalCaseCustomField; import io.metersphere.functional.domain.FunctionalCaseCustomFieldExample; @@ -8,6 +9,7 @@ import io.metersphere.functional.mapper.ExtFunctionalCaseMapper; import io.metersphere.functional.mapper.FunctionalCaseCustomFieldMapper; import io.metersphere.functional.mapper.FunctionalCaseMapper; import io.metersphere.functional.request.FunctionalCaseBatchRequest; +import io.metersphere.functional.utils.CaseListenerUtils; import io.metersphere.sdk.exception.MSException; import io.metersphere.sdk.util.Translator; import io.metersphere.system.domain.CustomField; @@ -15,12 +17,13 @@ import io.metersphere.system.domain.CustomFieldExample; import io.metersphere.system.mapper.CustomFieldMapper; import jakarta.annotation.Resource; import org.apache.commons.collections.CollectionUtils; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @author guoyuqi @@ -55,10 +58,15 @@ public class FunctionalCaseTrashService { List ids = getIdsByRefId(functionalCase.getRefId()); //检查自定义字段是否还存在,不存在,删除关联关系(与恢复流程没关系可异步执行) delCustomFields(ids); + Map param = new HashMap<>(); + param.put(CaseEvent.Param.CASE_IDS,ids); + CaseListenerUtils.addListener(param, CaseEvent.Event.RECOVER_FUNCTIONAL_CASE); extFunctionalCaseMapper.recoverCase(ids,userId,System.currentTimeMillis()); } - + /** + * 检查自定义字段是否还存在,不存在,删除关联关系(与恢复流程没关系可异步执行) + */ public void delCustomFields(List ids) { doDeleteCustomFields(ids); } @@ -102,6 +110,9 @@ public class FunctionalCaseTrashService { return; } List ids = getIdsByRefId(functionalCase.getRefId()); + Map param = new HashMap<>(); + param.put(CaseEvent.Param.CASE_IDS,ids); + CaseListenerUtils.addListener(param, CaseEvent.Event.DELETE_TRASH_FUNCTIONAL_CASE); deleteFunctionalCaseService.deleteFunctionalCaseResource(ids, functionalCase.getProjectId()); } @@ -134,6 +145,13 @@ public class FunctionalCaseTrashService { refIds = functionalCases.stream().map(FunctionalCase::getRefId).distinct().toList(); } if (CollectionUtils.isNotEmpty(refIds)) { + FunctionalCaseExample functionalCaseExample = new FunctionalCaseExample(); + functionalCaseExample.createCriteria().andRefIdIn(refIds); + List functionalCases = functionalCaseMapper.selectByExample(functionalCaseExample); + List ids = functionalCases.stream().map(FunctionalCase::getId).toList(); + Map param = new HashMap<>(); + param.put(CaseEvent.Param.CASE_IDS,ids); + CaseListenerUtils.addListener(param, CaseEvent.Event.RECOVER_FUNCTIONAL_CASE); extFunctionalCaseMapper.recoverCaseByRefIds(refIds, userId, System.currentTimeMillis()); delCustomFieldsByRefIds(refIds); } @@ -175,6 +193,9 @@ public class FunctionalCaseTrashService { deleteByRefIds(request, refIds); }else { //只删除当前选择的数据 + Map param = new HashMap<>(); + param.put(CaseEvent.Param.CASE_IDS,ids); + CaseListenerUtils.addListener(param, CaseEvent.Event.DELETE_TRASH_FUNCTIONAL_CASE); deleteFunctionalCaseService.deleteFunctionalCaseResource(ids, request.getProjectId()); } } else { @@ -189,6 +210,9 @@ public class FunctionalCaseTrashService { deleteByRefIds(request, refIds); } else { //只删除当前选择的数据 + Map param = new HashMap<>(); + param.put(CaseEvent.Param.CASE_IDS,request.getSelectIds()); + CaseListenerUtils.addListener(param, CaseEvent.Event.DELETE_TRASH_FUNCTIONAL_CASE); deleteFunctionalCaseService.deleteFunctionalCaseResource(request.getSelectIds(), request.getProjectId()); } } @@ -199,6 +223,9 @@ public class FunctionalCaseTrashService { functionalCaseExample.createCriteria().andRefIdIn(refIds).andDeletedEqualTo(true); List functionalCases = functionalCaseMapper.selectByExample(functionalCaseExample); List deleteIds = functionalCases.stream().map(FunctionalCase::getId).toList(); + Map param = new HashMap<>(); + param.put(CaseEvent.Param.CASE_IDS,deleteIds); + CaseListenerUtils.addListener(param, CaseEvent.Event.DELETE_TRASH_FUNCTIONAL_CASE); deleteFunctionalCaseService.deleteFunctionalCaseResource(deleteIds, request.getProjectId()); } } diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/ReviewFunctionalCaseService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/ReviewFunctionalCaseService.java index 9fb151cf95..6414af46e3 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/ReviewFunctionalCaseService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/ReviewFunctionalCaseService.java @@ -19,7 +19,6 @@ import io.metersphere.system.uid.IDGenerator; import jakarta.annotation.Resource; import org.apache.commons.beanutils.BeanMap; import org.apache.commons.lang3.StringUtils; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -51,7 +50,6 @@ public class ReviewFunctionalCaseService { private ExtCaseReviewHistoryMapper extCaseReviewHistoryMapper; - /** * 评审功能用例 * @@ -66,7 +64,7 @@ public class ReviewFunctionalCaseService { String functionalCaseStatus = getFunctionalCaseStatus(request); extCaseReviewFunctionalCaseMapper.updateStatus(request.getCaseId(), request.getReviewId(), functionalCaseStatus); //更新用例评审状态(判断所有用例是否结束,false:进行中,true:已完成) - boolean completed = updateCaseReviewStatus(request.getCaseId(), request.getReviewId()); + boolean completed = updateCaseReviewStatus(request.getReviewId()); //检查是否有@,发送@通知 if (StringUtils.isNotBlank(request.getNotifier())) { List relatedUsers = Arrays.asList(request.getNotifier().split(";")); @@ -120,11 +118,10 @@ public class ReviewFunctionalCaseService { /** * 更新用例评审自身的状态 * - * @param caseId 功能用例Id * @param reviewId 用例评审Id * @return completed */ - private boolean updateCaseReviewStatus(String caseId, String reviewId) { + private boolean updateCaseReviewStatus(String reviewId) { boolean completed = false; List statusList = new ArrayList<>(); statusList.add(FunctionalCaseReviewStatus.UN_REVIEWED.toString()); diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/utils/CaseListenerUtils.java b/backend/services/case-management/src/main/java/io/metersphere/functional/utils/CaseListenerUtils.java new file mode 100644 index 0000000000..66d3072514 --- /dev/null +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/utils/CaseListenerUtils.java @@ -0,0 +1,23 @@ +package io.metersphere.functional.utils; + +import io.metersphere.functional.event.CaseEventSource; +import io.metersphere.functional.listener.CaseEventListener; +import io.metersphere.sdk.util.CommonBeanFactory; + +import java.util.Map; + +public class CaseListenerUtils { + + public static void addListener(Map param, String message) { + CaseEventSource caseEventSource = CommonBeanFactory.getBean(CaseEventSource.class); + CaseEventListener caseEventListener = CommonBeanFactory.getBean(CaseEventListener.class); + if (caseEventSource != null) { + caseEventSource.addListener(event -> { + assert caseEventListener != null; + caseEventListener.onEvent(event); + }); + caseEventSource.fireEvent("CASE_MANAGEMENT", message, param); + } + } + +} diff --git a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java index 2b5aea3e66..60b4c9cc86 100644 --- a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java +++ b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/CaseReviewControllerTests.java @@ -301,6 +301,8 @@ public class CaseReviewControllerTests extends BaseTest { List userIdList = caseReviewFunctionalCaseUsers.stream().map(CaseReviewFunctionalCaseUser::getUserId).toList(); Assertions.assertTrue(userIdList.contains("gyq_review_test")); Assertions.assertTrue(userIdList.contains("gyq_review_test2")); + List caseReviews2 = getCaseReviews("创建评审更新1"); + Assertions.assertTrue( caseReviews.get(0).getCaseCount()()); request.setSelectAll(true); + request.setExcludeIds(Arrays.asList("TEST_FUNCTIONAL_CASE_ID_1")); Map map = new HashMap<>(); map.put("customs", Arrays.asList(new LinkedHashMap() {{ put("id", "TEST_FIELD_ID"); diff --git a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/EventSourceTests.java b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/EventSourceTests.java new file mode 100644 index 0000000000..7f536eb725 --- /dev/null +++ b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/EventSourceTests.java @@ -0,0 +1,41 @@ +package io.metersphere.functional.controller; + +import io.metersphere.functional.event.CaseEventSource; +import io.metersphere.sdk.listener.Event; +import io.metersphere.sdk.listener.EventListener; +import io.metersphere.sdk.util.CommonBeanFactory; +import io.metersphere.sdk.util.LogUtils; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.HashMap; + + +@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@AutoConfigureMockMvc +public class EventSourceTests { + + @Test + @Order(0) + public void eventSourceTest() throws Exception { + // 注册所有监听源 + LogUtils.info("初始化用例管理事件源"); + CaseEventSource caseEventSource = CommonBeanFactory.getBean(CaseEventSource.class); + assert caseEventSource != null; + caseEventSource.addListener(new EventListener() { + @Override + public void onEvent(Event event) { + LogUtils.info("ExecEventListener: " + event.module() + ":" + event.message()); + } + }); + // 触发事件 + caseEventSource.fireEvent("CASE", "Event after removing the listener test."); + // 触发事件待参数 + caseEventSource.fireEvent("CASE", "Event after removing the listener test.",new HashMap<>()); + } +} diff --git a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseTrashControllerTests.java b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseTrashControllerTests.java index 89fc11d926..ca44e57bf4 100644 --- a/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseTrashControllerTests.java +++ b/backend/services/case-management/src/test/java/io/metersphere/functional/controller/FunctionalCaseTrashControllerTests.java @@ -196,6 +196,8 @@ public class FunctionalCaseTrashControllerTests extends BaseTest { Assertions.assertNull(functionalCase4); FunctionalCaseComment functionalCaseComment = functionalCaseCommentMapper.selectByPrimaryKey("trash_comment_id"); Assertions.assertNull(functionalCaseComment); + this.requestGetWithOk(URL_CASE_DELETE + "Trash_TEST_FUNCTIONAL_CASE_ID_GYQ"); + } diff --git a/backend/services/case-management/src/test/resources/dml/init_case_trash.sql b/backend/services/case-management/src/test/resources/dml/init_case_trash.sql index 37b9d6241b..822fdfa31c 100644 --- a/backend/services/case-management/src/test/resources/dml/init_case_trash.sql +++ b/backend/services/case-management/src/test/resources/dml/init_case_trash.sql @@ -63,7 +63,14 @@ VALUES ('Trash_TEST_FUNCTIONAL_CASE_ID_f', 7, 'Trash_TEST_MOUDLE_ID_1', 'project INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time) VALUES ('Trash_TEST_FUNCTIONAL_CASE_ID_g', 8, 'Trash_TEST_MOUDLE_ID_1', 'project-case-trash-test-2', '100001', 'copy_测试多版本g', 'UN_REVIEWED', NULL, 'STEP', 0, 'v3.0.0', 'Trash_TEST_FUNCTIONAL_CASE_ID_f', 'UN_EXECUTED',true, b'0', b'1', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL); +INSERT INTO functional_case(id, num, module_id, project_id, template_id, name, review_status, tags, case_edit_type, pos, version_id, ref_id, last_execute_result, deleted, public_case, latest, create_user, update_user, delete_user, create_time, update_time, delete_time) +VALUES ('Trash_TEST_FUNCTIONAL_CASE_ID_GYQ', 100, 'Trash_TEST_MOUDLE_ID', 'project-case-trash-test', '100001', '回收站测信', 'UN_REVIEWED', NULL, 'STEP', 0, 'v1.0.0', 'Trash_TEST_FUNCTIONAL_CASE_ID_GYQ', 'UN_EXECUTED', true, b'0', b'0', 'gyq', 'gyq', '', 1698058347559, 1698058347559, NULL); +INSERT INTO case_review_functional_case(id, review_id, case_id, status, create_time, create_user, update_time, pos) +VALUES ('Gyq_Review_Case_Id','Gyq_review_id', 'Trash_TEST_FUNCTIONAL_CASE_ID', 'PASS', 1698058347559, 'admin',1698058347559, 0); + +INSERT INTO case_review(id, num, name, module_id, project_id, status, review_pass_rule, pos, start_time, end_time, case_count, pass_rate, tags, description, create_time, create_user, update_time, update_user) +VALUES ('Gyq_review_id', 10001, '用例评审1', 'Trash_TEST_MOUDLE_ID_1', 'project-case-trash-test', 'COMPLETE' , 'SINGLE', 0, 1698058347559, 1698058347559, 1, 100.00, null, null, 1698058347559, 'admin', 1698058347559, 'admin'); INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('Trash_TEST_FUNCTIONAL_CASE_ID', 'gyq_custom_id1', '22'); INSERT INTO functional_case_custom_field(case_id, field_id, value) VALUES ('Trash_TEST_FUNCTIONAL_CASE_ID', 'gyq_custom_id2', '33');