feat(bi): paginate company online personnel stats

dev
shenzhidan 2026-08-03 14:41:12 +08:00
parent c237fdbcc8
commit ea1beb4f02
8 changed files with 158 additions and 9 deletions

View File

@ -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<BiCompanyOnlinePersonStatCO> queryCompanyOnlinePersonStat(
@RequestBody BiCompanyOnlinePersonQry qry) {
@RequestBody BiCompanyOnlinePersonStatQry qry) {
return SingleResponse.of(personnelPositioningBiService.queryCompanyOnlinePersonStat(qry));
}
@ApiOperation("可视化大屏-人员定位列表")

View File

@ -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<CorpInfoView> corpInfos = queryCompanyOnlineCorpInfos(query);
List<BiCompanyOnlinePersonCO> 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;
}

View File

@ -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);
}

View File

@ -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<BiCompanyOnlinePersonCO> 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.<BiCompanyOnlinePersonCO>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;
}
}

View File

@ -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<BiPersonPositionCO> listPersonPosition(BiPersonPositionQry qry);
BiCompanyOnlinePersonStatCO queryCompanyOnlinePersonStat(BiCompanyOnlinePersonQry qry);
BiCompanyOnlinePersonStatCO queryCompanyOnlinePersonStat(BiCompanyOnlinePersonStatQry qry);
BiPersonTraceCO queryPersonTrace(BiPersonTraceQry qry);

View File

@ -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;
}

View File

@ -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<BiCompanyOnlinePersonCO> personList;
}

View File

@ -70,7 +70,7 @@
AND <include refid="mappedCompanyId"/> = CAST(#{params.corpinfoId} AS CHAR)
</if>
<if test="params.portArea != null">
AND COALESCE(corp_uuid.port_area, corp_internal.port_area) = #{params.portArea}
AND corp.port_area = #{params.portArea}
</if>
ORDER BY COALESCE(ar.start_time, ar.create_time) DESC, ar.id DESC
</select>