From ea1beb4f02a2db1c09d489b787c030255c7cd0a0 Mon Sep 17 00:00:00 2001 From: shenzhidan Date: Mon, 3 Aug 2026 14:41:12 +0800 Subject: [PATCH] feat(bi): paginate company online personnel stats --- .../web/PersonnelPositioningBiController.java | 3 +- .../query/PersonnelPositioningBiQueryExe.java | 23 +++- .../PersonnelPositioningBiServiceImpl.java | 3 +- ...CompanyOnlinePersonStatPaginationTest.java | 103 ++++++++++++++++++ .../api/PersonnelPositioningBiServiceI.java | 3 +- .../dto/BiCompanyOnlinePersonStatQry.java | 21 ++++ .../BiCompanyOnlinePersonStatCO.java | 9 ++ .../resources/mapper/AlarmRecordMapper.xml | 2 +- 8 files changed, 158 insertions(+), 9 deletions(-) create mode 100644 web-app/src/test/java/com/zcloud/personnel/positioning/command/query/CompanyOnlinePersonStatPaginationTest.java create mode 100644 web-client/src/main/java/com/zcloud/personnel/positioning/dto/BiCompanyOnlinePersonStatQry.java diff --git a/web-adapter/src/main/java/com/zcloud/personnel/positioning/web/PersonnelPositioningBiController.java b/web-adapter/src/main/java/com/zcloud/personnel/positioning/web/PersonnelPositioningBiController.java index 11199a3..e9b4e73 100644 --- a/web-adapter/src/main/java/com/zcloud/personnel/positioning/web/PersonnelPositioningBiController.java +++ b/web-adapter/src/main/java/com/zcloud/personnel/positioning/web/PersonnelPositioningBiController.java @@ -7,6 +7,7 @@ import com.zcloud.personnel.positioning.api.PersonnelPositioningBiServiceI; import com.zcloud.personnel.positioning.dto.BiAreaFenceQry; import com.zcloud.personnel.positioning.dto.BiCompanyFenceQry; import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonQry; +import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonStatQry; import com.zcloud.personnel.positioning.dto.BiPersonLocationQry; import com.zcloud.personnel.positioning.dto.BiPersonPositionQry; import com.zcloud.personnel.positioning.dto.BiPersonTraceQry; @@ -96,7 +97,7 @@ public class PersonnelPositioningBiController { @ApiOperation("可视化大屏-企业在线人员统计") @PostMapping("/personLocation/companyOnlineStat") public SingleResponse queryCompanyOnlinePersonStat( - @RequestBody BiCompanyOnlinePersonQry qry) { + @RequestBody BiCompanyOnlinePersonStatQry qry) { return SingleResponse.of(personnelPositioningBiService.queryCompanyOnlinePersonStat(qry)); } @ApiOperation("可视化大屏-人员定位列表") diff --git a/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PersonnelPositioningBiQueryExe.java b/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PersonnelPositioningBiQueryExe.java index 96b6d59..fe57138 100644 --- a/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PersonnelPositioningBiQueryExe.java +++ b/web-app/src/main/java/com/zcloud/personnel/positioning/command/query/PersonnelPositioningBiQueryExe.java @@ -10,6 +10,7 @@ import com.jjb.saas.framework.auth.utils.AuthContext; import com.zcloud.personnel.positioning.dto.BiAreaFenceQry; import com.zcloud.personnel.positioning.dto.BiCompanyFenceQry; import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonQry; +import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonStatQry; import com.zcloud.personnel.positioning.dto.BiPersonLocationQry; import com.zcloud.personnel.positioning.dto.BiPersonPositionQry; import com.zcloud.personnel.positioning.dto.BiPersonTraceQry; @@ -440,8 +441,8 @@ public class PersonnelPositioningBiQueryExe { return inside; } - public BiCompanyOnlinePersonStatCO queryCompanyOnlinePersonStat(BiCompanyOnlinePersonQry qry) { - BiCompanyOnlinePersonQry query = qry == null ? new BiCompanyOnlinePersonQry() : qry; + public BiCompanyOnlinePersonStatCO queryCompanyOnlinePersonStat(BiCompanyOnlinePersonStatQry qry) { + BiCompanyOnlinePersonStatQry query = qry == null ? new BiCompanyOnlinePersonStatQry() : qry; validatePortArea(query.getPortArea()); List corpInfos = queryCompanyOnlineCorpInfos(query); List personList = new ArrayList<>(); @@ -459,8 +460,9 @@ public class PersonnelPositioningBiQueryExe { return Long.compare(rightTime, leftTime); }); BiCompanyOnlinePersonStatCO co = new BiCompanyOnlinePersonStatCO(); - co.setPersonList(personList); - co.setOnlineCount(personList.size()); + int totalCount = personList.size(); + co.setOnlineCount(totalCount); + co.setTotalCount(totalCount); int internalCount = 0; for (BiCompanyOnlinePersonCO person : personList) { if (Boolean.TRUE.equals(person.getInternalEmployee())) { @@ -468,7 +470,18 @@ public class PersonnelPositioningBiQueryExe { } } co.setInternalCount(internalCount); - co.setTemporaryCount(personList.size() - internalCount); + co.setTemporaryCount(totalCount - internalCount); + if (query.getPageIndex() == null && query.getPageSize() == null) { + co.setPersonList(personList); + return co; + } + int pageIndex = Math.max(query.getPageIndex() == null ? 1 : query.getPageIndex(), 1); + int pageSize = Math.max(query.getPageSize() == null ? 10 : query.getPageSize(), 1); + int fromIndex = (int) Math.min((long) (pageIndex - 1) * pageSize, totalCount); + int toIndex = (int) Math.min((long) fromIndex + pageSize, totalCount); + co.setPageIndex(pageIndex); + co.setPageSize(pageSize); + co.setPersonList(new ArrayList<>(personList.subList(fromIndex, toIndex))); return co; } diff --git a/web-app/src/main/java/com/zcloud/personnel/positioning/service/PersonnelPositioningBiServiceImpl.java b/web-app/src/main/java/com/zcloud/personnel/positioning/service/PersonnelPositioningBiServiceImpl.java index ae1cac9..92f4339 100644 --- a/web-app/src/main/java/com/zcloud/personnel/positioning/service/PersonnelPositioningBiServiceImpl.java +++ b/web-app/src/main/java/com/zcloud/personnel/positioning/service/PersonnelPositioningBiServiceImpl.java @@ -5,6 +5,7 @@ import com.zcloud.personnel.positioning.api.PersonnelPositioningBiServiceI; import com.zcloud.personnel.positioning.command.query.PersonnelPositioningBiQueryExe; import com.zcloud.personnel.positioning.dto.BiAreaFenceQry; import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonQry; +import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonStatQry; import com.zcloud.personnel.positioning.dto.BiCompanyFenceQry; import com.zcloud.personnel.positioning.dto.BiPersonLocationQry; import com.zcloud.personnel.positioning.dto.BiPersonPositionQry; @@ -70,7 +71,7 @@ public class PersonnelPositioningBiServiceImpl implements PersonnelPositioningBi } @Override - public BiCompanyOnlinePersonStatCO queryCompanyOnlinePersonStat(BiCompanyOnlinePersonQry qry) { + public BiCompanyOnlinePersonStatCO queryCompanyOnlinePersonStat(BiCompanyOnlinePersonStatQry qry) { return personnelPositioningBiQueryExe.queryCompanyOnlinePersonStat(qry); } diff --git a/web-app/src/test/java/com/zcloud/personnel/positioning/command/query/CompanyOnlinePersonStatPaginationTest.java b/web-app/src/test/java/com/zcloud/personnel/positioning/command/query/CompanyOnlinePersonStatPaginationTest.java new file mode 100644 index 0000000..677acc1 --- /dev/null +++ b/web-app/src/test/java/com/zcloud/personnel/positioning/command/query/CompanyOnlinePersonStatPaginationTest.java @@ -0,0 +1,103 @@ +package com.zcloud.personnel.positioning.command.query; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonStatQry; +import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyOnlinePersonCO; +import com.zcloud.personnel.positioning.dto.clientobject.BiCompanyOnlinePersonStatCO; +import com.zcloud.personnel.positioning.integration.finds.FindsOpenApiClient; +import com.zcloud.personnel.positioning.persistence.dataobject.BiCorpInfoDO; +import com.zcloud.personnel.positioning.persistence.repository.AreaRepository; +import com.zcloud.personnel.positioning.persistence.repository.FenceRepository; +import com.zcloud.personnel.positioning.persistence.repository.PersonnelPositioningBiRepository; +import com.zcloud.personnel.positioning.persistence.repository.UserRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class CompanyOnlinePersonStatPaginationTest { + private PersonnelPositioningBiRepository biRepository; + private BiPersonLocationProvider personLocationProvider; + private PersonnelPositioningBiQueryExe queryExe; + + @BeforeEach + void setUp() { + biRepository = mock(PersonnelPositioningBiRepository.class); + personLocationProvider = mock(BiPersonLocationProvider.class); + queryExe = new PersonnelPositioningBiQueryExe( + mock(FindsOpenApiClient.class), new ObjectMapper(), biRepository, + mock(AreaRepository.class), mock(FenceRepository.class), mock(UserRepository.class), + personLocationProvider, mock(BiOverviewCache.class), + mock(PositionPersonLocalLookupService.class)); + stubCompanyAndPeople(); + } + + @Test + void returnsAllPeopleWhenPaginationIsNotProvided() { + BiCompanyOnlinePersonStatCO response = + queryExe.queryCompanyOnlinePersonStat(new BiCompanyOnlinePersonStatQry()); + + assertEquals(3, response.getOnlineCount()); + assertEquals(2, response.getInternalCount()); + assertEquals(1, response.getTemporaryCount()); + assertEquals(3, response.getTotalCount()); + assertEquals(3, response.getPersonList().size()); + assertEquals("Person 3", response.getPersonList().get(0).getStaffName()); + assertNull(response.getPageIndex()); + assertNull(response.getPageSize()); + } + + @Test + void returnsRequestedPageWithoutChangingAggregateCounts() { + BiCompanyOnlinePersonStatQry qry = new BiCompanyOnlinePersonStatQry(); + qry.setPageIndex(2); + qry.setPageSize(1); + + BiCompanyOnlinePersonStatCO response = queryExe.queryCompanyOnlinePersonStat(qry); + + assertEquals(3, response.getOnlineCount()); + assertEquals(2, response.getInternalCount()); + assertEquals(1, response.getTemporaryCount()); + assertEquals(3, response.getTotalCount()); + assertEquals(2, response.getPageIndex()); + assertEquals(1, response.getPageSize()); + assertEquals(1, response.getPersonList().size()); + assertEquals("Person 2", response.getPersonList().get(0).getStaffName()); + } + + private void stubCompanyAndPeople() { + BiCorpInfoDO company = new BiCorpInfoDO(); + company.setCorpinfoId(2001L); + company.setCorpName("Company"); + company.setCode("COMPANY-CODE"); + when(biRepository.listCorpInfos(null)).thenReturn(Collections.singletonList(company)); + + List people = Arrays.asList( + onlinePerson("Person 1", 1000L, true), + onlinePerson("Person 2", 2000L, false), + onlinePerson("Person 3", 3000L, true)); + when(personLocationProvider.listCompanyOnlinePersons(2001L, "Company", "COMPANY-CODE")) + .thenReturn(people); + when(personLocationProvider.isOnline(any(BiCompanyOnlinePersonCO.class))) + .thenAnswer(invocation -> "ONLINE".equals( + invocation.getArgument(0).getLocationStatus())); + } + + private BiCompanyOnlinePersonCO onlinePerson(String name, long lastLocationTime, + boolean internalEmployee) { + BiCompanyOnlinePersonCO person = new BiCompanyOnlinePersonCO(); + person.setStaffName(name); + person.setLastLocationTime(lastLocationTime); + person.setLocationStatus("ONLINE"); + person.setInternalEmployee(internalEmployee); + return person; + } +} diff --git a/web-client/src/main/java/com/zcloud/personnel/positioning/api/PersonnelPositioningBiServiceI.java b/web-client/src/main/java/com/zcloud/personnel/positioning/api/PersonnelPositioningBiServiceI.java index a8fadb5..6204650 100644 --- a/web-client/src/main/java/com/zcloud/personnel/positioning/api/PersonnelPositioningBiServiceI.java +++ b/web-client/src/main/java/com/zcloud/personnel/positioning/api/PersonnelPositioningBiServiceI.java @@ -3,6 +3,7 @@ package com.zcloud.personnel.positioning.api; import com.alibaba.cola.dto.PageResponse; import com.zcloud.personnel.positioning.dto.BiAreaFenceQry; import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonQry; +import com.zcloud.personnel.positioning.dto.BiCompanyOnlinePersonStatQry; import com.zcloud.personnel.positioning.dto.BiCompanyFenceQry; import com.zcloud.personnel.positioning.dto.BiPersonLocationQry; import com.zcloud.personnel.positioning.dto.BiPersonPositionQry; @@ -40,7 +41,7 @@ public interface PersonnelPositioningBiServiceI { PageResponse listPersonPosition(BiPersonPositionQry qry); - BiCompanyOnlinePersonStatCO queryCompanyOnlinePersonStat(BiCompanyOnlinePersonQry qry); + BiCompanyOnlinePersonStatCO queryCompanyOnlinePersonStat(BiCompanyOnlinePersonStatQry qry); BiPersonTraceCO queryPersonTrace(BiPersonTraceQry qry); diff --git a/web-client/src/main/java/com/zcloud/personnel/positioning/dto/BiCompanyOnlinePersonStatQry.java b/web-client/src/main/java/com/zcloud/personnel/positioning/dto/BiCompanyOnlinePersonStatQry.java new file mode 100644 index 0000000..5f7c9a4 --- /dev/null +++ b/web-client/src/main/java/com/zcloud/personnel/positioning/dto/BiCompanyOnlinePersonStatQry.java @@ -0,0 +1,21 @@ +package com.zcloud.personnel.positioning.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * BI企业在线人员统计查询参数。 + * + * @Author Codex + * @Date 2026-08-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class BiCompanyOnlinePersonStatQry extends BiCompanyOnlinePersonQry { + @ApiModelProperty(value = "页码,从1开始;分页参数均未传时返回全部", name = "pageIndex") + private Integer pageIndex; + + @ApiModelProperty(value = "每页条数;分页参数均未传时返回全部", name = "pageSize") + private Integer pageSize; +} diff --git a/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/BiCompanyOnlinePersonStatCO.java b/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/BiCompanyOnlinePersonStatCO.java index 7a79aa6..0f438db 100644 --- a/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/BiCompanyOnlinePersonStatCO.java +++ b/web-client/src/main/java/com/zcloud/personnel/positioning/dto/clientobject/BiCompanyOnlinePersonStatCO.java @@ -23,6 +23,15 @@ public class BiCompanyOnlinePersonStatCO extends ClientObject { @ApiModelProperty(value = "临时人员数量", name = "temporaryCount") private Integer temporaryCount; + @ApiModelProperty(value = "在线人员总条数", name = "totalCount") + private Integer totalCount; + + @ApiModelProperty(value = "当前页码,未启用分页时为空", name = "pageIndex") + private Integer pageIndex; + + @ApiModelProperty(value = "每页条数,未启用分页时为空", name = "pageSize") + private Integer pageSize; + @ApiModelProperty(value = "在线人员列表", name = "personList") private List personList; } diff --git a/web-infrastructure/src/main/resources/mapper/AlarmRecordMapper.xml b/web-infrastructure/src/main/resources/mapper/AlarmRecordMapper.xml index 2fcc89c..f416129 100644 --- a/web-infrastructure/src/main/resources/mapper/AlarmRecordMapper.xml +++ b/web-infrastructure/src/main/resources/mapper/AlarmRecordMapper.xml @@ -70,7 +70,7 @@ AND = CAST(#{params.corpinfoId} AS CHAR) - AND COALESCE(corp_uuid.port_area, corp_internal.port_area) = #{params.portArea} + AND corp.port_area = #{params.portArea} ORDER BY COALESCE(ar.start_time, ar.create_time) DESC, ar.id DESC