🐛 首页异常处置红点只数待处理

- 快捷入口红点由 disposalStatus≠completed 改为 =pending,处置中的不再计入待办
- 补充 ManageAdminHomeBadgeTest
This commit is contained in:
2026-10-28 18:48:31 +08:00
parent afe651f612
commit 077848a0f6
3 changed files with 148 additions and 2 deletions
@@ -38,7 +38,7 @@ public class AdminHomeBadgesVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Schema(description = "异常处置待办数(disposalStatus≠completed)")
@Schema(description = "异常处置待办数(disposalStatus=pending)")
private long exception;
@Schema(description = "风险记录待办数(disposalStatus=pending)")
@@ -170,7 +170,8 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
home.setStats(stats());
AdminHomeBadgesVO badges = new AdminHomeBadgesVO();
badges.setException(home.getStats().getException());
// 快捷入口的红点是待办数,只数待处理:处置中的已经在跟,不再提醒
badges.setException(countPendingExceptions());
badges.setRisk(countPendingRisks());
badges.setPendingReassign(countPendingReassignments());
home.setBadges(badges);
@@ -1213,6 +1214,14 @@ public class ManageWaybillServiceImpl implements IManageWaybillService {
return exceptionDisposalService.count(wrapper);
}
/** 快捷入口「异常处置」红点:只数待处理(pending),处置中已不算待办 */
private long countPendingExceptions() {
LambdaQueryWrapper<ExceptionDisposal> wrapper = Wrappers.<ExceptionDisposal>lambdaQuery()
.eq(ExceptionDisposal::getDisposalStatus, DISPOSAL_PENDING);
applyExceptionDeptScope(wrapper);
return exceptionDisposalService.count(wrapper);
}
private long countPendingRisks() {
LambdaQueryWrapper<RiskDisposal> wrapper = Wrappers.<RiskDisposal>lambdaQuery()
.eq(RiskDisposal::getDisposalStatus, RISK_PENDING);
@@ -0,0 +1,137 @@
package org.springblade.transport.service.impl;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.MockedStatic;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.system.cache.UserDisplayCache;
import org.springblade.transport.pojo.entity.ExceptionDisposal;
import org.springblade.transport.pojo.entity.Waybill;
import org.springblade.transport.pojo.vo.AdminHomeVO;
import org.springblade.transport.pojo.vo.TripTabCountsVO;
import org.springblade.transport.service.IDriverService;
import org.springblade.transport.service.IDriverWaybillService;
import org.springblade.transport.service.IExceptionDisposalService;
import org.springblade.transport.service.ILoadingManageService;
import org.springblade.transport.service.IRiskDisposalService;
import org.springblade.transport.service.ITripQueryService;
import org.springblade.transport.service.IWaybillService;
import org.springblade.transport.support.MpUserDataScopeSupport;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* 调度端首页「异常处置」快捷入口的红点:只数待处理(pending)的异常。
* <p>
* 统计卡的「在途异常」仍按未了结(pending + processing)算,两处口径不同:红点是待办提醒,
* 处置中的异常已经在跟进,再算进红点会让它一直清不掉。
* <p>
* 这里走 {@code home()}:红点是聚合接口里的字段,只测计数方法证明不了它接在哪一处。
*/
class ManageAdminHomeBadgeTest {
private static final String DEPT_ID = "1123598813738675201";
private static final Long USER_ID = 1900000000000000001L;
private static final long PENDING_COUNT = 3L;
private static final long INCOMPLETE_COUNT = 7L;
private ManageWaybillServiceImpl service;
private IExceptionDisposalService exceptionService;
private MockedStatic<AuthUtil> authUtil;
@BeforeAll
static void initTableInfo() {
MybatisConfiguration configuration = new MybatisConfiguration();
MapperBuilderAssistant assistant = new MapperBuilderAssistant(configuration, "");
assistant.setCurrentNamespace("test");
TableInfoHelper.initTableInfo(assistant, Waybill.class);
TableInfoHelper.initTableInfo(assistant, ExceptionDisposal.class);
}
@BeforeEach
void setUp() {
IWaybillService waybillService = mock(IWaybillService.class);
exceptionService = mock(IExceptionDisposalService.class);
ITripQueryService tripQueryService = mock(ITripQueryService.class);
when(tripQueryService.tabCounts(ArgumentMatchers.any())).thenReturn(new TripTabCountsVO());
when(exceptionService.list(ArgumentMatchers.<Wrapper<ExceptionDisposal>>any()))
.thenReturn(new ArrayList<>());
when(waybillService.list(ArgumentMatchers.<Wrapper<Waybill>>any())).thenReturn(new ArrayList<>());
// 待重新派单的分页查询回它收到的 Page(总数从入参上读,回 null 会空指针)
when(waybillService.page(ArgumentMatchers.any(), ArgumentMatchers.any()))
.thenAnswer(invocation -> invocation.getArgument(0));
// 处置状态的计数被查两次:带 processing 的是「未了结」,只带 pending 的是「待处理」
when(exceptionService.count(ArgumentMatchers.<Wrapper<ExceptionDisposal>>any()))
.thenAnswer(invocation -> coversProcessing(invocation.getArgument(0)) ? INCOMPLETE_COUNT : PENDING_COUNT);
service = new ManageWaybillServiceImpl(
waybillService,
mock(IDriverService.class),
exceptionService,
mock(IRiskDisposalService.class),
mock(IDriverWaybillService.class),
tripQueryService,
mock(ILoadingManageService.class),
mock(MpUserDataScopeSupport.class));
authUtil = mockStatic(AuthUtil.class);
authUtil.when(AuthUtil::getUserRole).thenReturn("yewu");
authUtil.when(AuthUtil::getDeptId).thenReturn(DEPT_ID);
authUtil.when(AuthUtil::getUserId).thenReturn(USER_ID);
}
@AfterEach
void tearDown() {
authUtil.close();
}
@Test
@DisplayName("红点只数待处理,统计卡的在途异常仍是未了结数")
void exceptionBadgeCountsPendingOnly() {
AdminHomeVO home;
try (MockedStatic<UserDisplayCache> ignored = mockStatic(UserDisplayCache.class)) {
home = service.home();
}
assertEquals(PENDING_COUNT, home.getBadges().getException(), "处置中的异常不再计入红点");
assertEquals(INCOMPLETE_COUNT, home.getStats().getException(), "统计卡口径不变:pending + processing");
ArgumentCaptor<Wrapper<ExceptionDisposal>> captor = ArgumentCaptor.forClass(Wrapper.class);
verify(exceptionService, times(2)).count(captor.capture());
List<String> segments = captor.getAllValues().stream()
.map(ManageAdminHomeBadgeTest::sqlSegment)
.collect(Collectors.toList());
assertTrue(segments.stream().anyMatch(segment -> segment.contains("disposal_status IN")),
"统计卡仍要数未了结:处置状态取 pending 与 processing 两档:" + segments);
assertTrue(segments.stream().anyMatch(segment -> segment.contains("disposal_status = ")),
"红点只认待处理:处置状态是等值条件,不再带 processing:" + segments);
}
/** 计数条件里是否含处置中:带 IN 的才是「pending + processing」那次查询 */
private static boolean coversProcessing(Wrapper<ExceptionDisposal> wrapper) {
return sqlSegment(wrapper).contains("disposal_status IN");
}
private static String sqlSegment(Wrapper<ExceptionDisposal> wrapper) {
return ((AbstractWrapper<?, ?, ?>) wrapper).getSqlSegment();
}
}