Browse Source

feat(infra):重构人员进出统计逻辑并添加查询接口

- 新增 PersonInOutDTO 数据传输对象- 修改 PersonInOutInfo 实体类字段,使用 LocalDateTime 替代字符串日期
- 添加自定义 Mapper 方法 countActive 用于统计活跃设备数- 更新 PersonInOutService 接口及实现类,支持分页查询和最新记录查询
- 新增 WebInOutParams 和 WapInOutParams 请求参数类- 在控制器中添加进出事件统计查询接口
- 修复活跃率计算空指针问题
- 添加相关单元测试用例
chejianzheng 3 weeks ago
parent
commit
78b622049d
13 changed files with 245 additions and 29 deletions
  1. 13 1
      portal-service-application/src/main/java/com/hfln/portal/application/controller/wap/StatsController.java
  2. 8 0
      portal-service-application/src/main/java/com/hfln/portal/application/controller/web/WebStatsController.java
  3. 29 0
      portal-service-common/src/main/java/com/hfln/portal/common/dto/data/event/PersonInOutDTO.java
  4. 23 0
      portal-service-common/src/main/java/com/hfln/portal/common/request/event/WapInOutParams.java
  5. 23 0
      portal-service-common/src/main/java/com/hfln/portal/common/request/event/WebInOutParams.java
  6. 4 0
      portal-service-domain/src/main/java/com/hfln/portal/domain/gateway/WebStatsGateway.java
  7. 15 1
      portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/gateway/impl/WebStatsGatewayImpl.java
  8. 9 0
      portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/mapper/PersonInOutMapper.java
  9. 11 12
      portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/mqtt/handlers/PresenceChangeHandler.java
  10. 6 5
      portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/po/PersonInOutInfo.java
  11. 5 1
      portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/service/PersonInOutService.java
  12. 35 9
      portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/service/impl/PersonInOutServiceImpl.java
  13. 64 0
      portal-service-server/src/test/java/com/hfln/portal/test/service/PersonInOutServiceTest.java

+ 13 - 1
portal-service-application/src/main/java/com/hfln/portal/application/controller/wap/StatsController.java

@@ -6,11 +6,14 @@ import cn.hfln.framework.dto.ApiResult;
 import com.hfln.portal.common.dto.data.event.EventListDTO;
 import com.hfln.portal.common.dto.data.event.EventTypeDTO;
 import com.hfln.portal.common.dto.data.event.EventsDTO;
-import com.hfln.portal.common.request.event.WapEventsParams;
+import com.hfln.portal.common.dto.data.event.PersonInOutDTO;
 import com.hfln.portal.common.request.event.WapEventListParams;
+import com.hfln.portal.common.request.event.WapEventsParams;
+import com.hfln.portal.common.request.event.WebInOutParams;
 import com.hfln.portal.common.vo.PageRecord;
 import com.hfln.portal.domain.gateway.AlarmGateway;
 import com.hfln.portal.domain.gateway.StatsGateway;
+import com.hfln.portal.domain.gateway.WebStatsGateway;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
@@ -33,6 +36,9 @@ public class StatsController {
     @Autowired
     private AlarmGateway alarmGateway;
 
+    @Autowired
+    private WebStatsGateway webStatsGateway;
+
     @PostMapping("/alarmEventsQuery")
     @Operation(summary = "告警事件统计查询")
     public ApiResult<PageRecord<EventsDTO>> alarmEventsQuery(@Valid @RequestBody WapEventsParams params) {
@@ -51,6 +57,12 @@ public class StatsController {
         return ApiResult.success(statsGateway.fallQuery(params));
     }
 
+    @PostMapping("/inOutEventQuery")
+    @Operation(summary = "进入进出事件统计查询")
+    public ApiResult<PageRecord<PersonInOutDTO>> inOutEventQuery(@RequestBody @Valid WebInOutParams params) {
+        return ApiResult.success(webStatsGateway.inOutEventQuery(params));
+    }
+
     @GetMapping("/queryEventType")
     @Operation(summary = "告警事件类型查询")
     public ApiResult<List<EventTypeDTO>> queryEventType() {

+ 8 - 0
portal-service-application/src/main/java/com/hfln/portal/application/controller/web/WebStatsController.java

@@ -7,12 +7,14 @@ import cn.hfln.framework.dto.ApiResult;
 import com.hfln.portal.common.dto.data.device.OnoffDTO;
 import com.hfln.portal.common.dto.data.event.EventListDTO;
 import com.hfln.portal.common.dto.data.event.EventsDTO;
+import com.hfln.portal.common.dto.data.event.PersonInOutDTO;
 import com.hfln.portal.common.dto.data.stat.ScreenAlarmDTO;
 import com.hfln.portal.common.dto.data.stat.ScreenFallingDTO;
 import com.hfln.portal.common.dto.data.stat.ScreenStatsDTO;
 import com.hfln.portal.common.dto.data.user.UserDailyActiveDTO;
 import com.hfln.portal.common.request.event.EventListParams;
 import com.hfln.portal.common.request.event.WebEventsParams;
+import com.hfln.portal.common.request.event.WebInOutParams;
 import com.hfln.portal.common.request.stat.ScreenAlarmQueryParams;
 import com.hfln.portal.common.request.stat.ScreenFallingQueryParams;
 import com.hfln.portal.common.request.stat.ScreenStatQueryParams;
@@ -54,6 +56,12 @@ public class WebStatsController {
         return ApiResult.success(webStatsGateway.alarmEventsQuery(params));
     }
 
+    @PostMapping("/inOutEventQuery")
+    @Operation(summary = "进入进出事件统计查询")
+    public ApiResult<PageRecord<PersonInOutDTO>> inOutEventQuery(@RequestBody @Valid WebInOutParams params) {
+        return ApiResult.success(webStatsGateway.inOutEventQuery(params));
+    }
+
     @PostMapping("/queryUserDailyActive")
     @Operation(summary = "查询用户日活跃")
     public ApiResult<PageRecord<UserDailyActiveDTO>> queryUserDailyActive(@Valid @RequestBody UserDailyActiveParams params) {

+ 29 - 0
portal-service-common/src/main/java/com/hfln/portal/common/dto/data/event/PersonInOutDTO.java

@@ -0,0 +1,29 @@
+package com.hfln.portal.common.dto.data.event;
+
+import com.hfln.portal.common.vo.BaseVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDateTime;
+
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class PersonInOutDTO extends BaseVO {
+
+    @Schema(description = "主键ID")
+    private Long perIoId;
+
+    @Schema(description = "租户表id")
+    private Long tenantId;
+
+    @Schema(description = "dev_info表id")
+    private Long devId;
+
+    @Schema(description = "进入时间")
+    private LocalDateTime enterTime;
+
+    @Schema(description = "离开时间")
+    private LocalDateTime leaveTime;
+}

+ 23 - 0
portal-service-common/src/main/java/com/hfln/portal/common/request/event/WapInOutParams.java

@@ -0,0 +1,23 @@
+package com.hfln.portal.common.request.event;
+
+import com.hfln.portal.common.vo.PageVo;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDate;
+
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class WapInOutParams extends PageVo {
+
+    @Schema(description = "设备ID")
+    private Long devId;
+
+    @Schema(description = "起始时间 格式yyyy-MM-dd")
+    private LocalDate createTimeStart;
+
+    @Schema(description = "结束时间 格式yyyy-MM-dd")
+    private LocalDate createTimeEnd;
+}

+ 23 - 0
portal-service-common/src/main/java/com/hfln/portal/common/request/event/WebInOutParams.java

@@ -0,0 +1,23 @@
+package com.hfln.portal.common.request.event;
+
+import com.hfln.portal.common.vo.PageVo;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.time.LocalDate;
+
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class WebInOutParams extends PageVo {
+
+    @Schema(description = "设备ID")
+    private Long devId;
+
+    @Schema(description = "起始时间 格式yyyy-MM-dd")
+    private LocalDate createTimeStart;
+
+    @Schema(description = "结束时间 格式yyyy-MM-dd")
+    private LocalDate createTimeEnd;
+}

+ 4 - 0
portal-service-domain/src/main/java/com/hfln/portal/domain/gateway/WebStatsGateway.java

@@ -3,12 +3,14 @@ package com.hfln.portal.domain.gateway;
 import com.hfln.portal.common.dto.data.device.OnoffDTO;
 import com.hfln.portal.common.dto.data.event.EventListDTO;
 import com.hfln.portal.common.dto.data.event.EventsDTO;
+import com.hfln.portal.common.dto.data.event.PersonInOutDTO;
 import com.hfln.portal.common.dto.data.stat.ScreenAlarmDTO;
 import com.hfln.portal.common.dto.data.stat.ScreenFallingDTO;
 import com.hfln.portal.common.dto.data.stat.ScreenStatsDTO;
 import com.hfln.portal.common.dto.data.user.UserDailyActiveDTO;
 import com.hfln.portal.common.request.event.EventListParams;
 import com.hfln.portal.common.request.event.WebEventsParams;
+import com.hfln.portal.common.request.event.WebInOutParams;
 import com.hfln.portal.common.request.stat.ScreenAlarmQueryParams;
 import com.hfln.portal.common.request.stat.ScreenFallingQueryParams;
 import com.hfln.portal.common.request.stat.ScreenStatQueryParams;
@@ -23,6 +25,8 @@ public interface WebStatsGateway {
 
     PageRecord<EventsDTO> alarmEventsQuery(WebEventsParams params);
 
+    PageRecord<PersonInOutDTO> inOutEventQuery(WebInOutParams params);
+
     PageRecord<UserDailyActiveDTO> queryUserDailyActive(UserDailyActiveParams params);
 
     ScreenStatsDTO queryScreen(ScreenStatQueryParams params);

+ 15 - 1
portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/gateway/impl/WebStatsGatewayImpl.java

@@ -6,12 +6,14 @@ import com.hfln.portal.common.constant.UserConstants;
 import com.hfln.portal.common.dto.data.device.OnoffDTO;
 import com.hfln.portal.common.dto.data.event.EventListDTO;
 import com.hfln.portal.common.dto.data.event.EventsDTO;
+import com.hfln.portal.common.dto.data.event.PersonInOutDTO;
 import com.hfln.portal.common.dto.data.stat.ScreenAlarmDTO;
 import com.hfln.portal.common.dto.data.stat.ScreenFallingDTO;
 import com.hfln.portal.common.dto.data.stat.ScreenStatsDTO;
 import com.hfln.portal.common.dto.data.user.UserDailyActiveDTO;
 import com.hfln.portal.common.request.event.EventListParams;
 import com.hfln.portal.common.request.event.WebEventsParams;
+import com.hfln.portal.common.request.event.WebInOutParams;
 import com.hfln.portal.common.request.stat.ScreenAlarmQueryParams;
 import com.hfln.portal.common.request.stat.ScreenFallingQueryParams;
 import com.hfln.portal.common.request.stat.ScreenStatQueryParams;
@@ -99,6 +101,14 @@ public class WebStatsGatewayImpl implements WebStatsGateway {
 
     }
 
+    @Override
+    public PageRecord<PersonInOutDTO> inOutEventQuery(WebInOutParams params) {
+
+        Page<PersonInOutInfo> page = personInOutService.selectPage(params);
+        List<PersonInOutDTO> dtoList = CopyUtils.copyList(page.getRecords(), PersonInOutDTO.class);
+        return CopyUtils.copyPage(page, dtoList);
+    }
+
 
     @Override
     public PageRecord<UserDailyActiveDTO> queryUserDailyActive(UserDailyActiveParams params) {
@@ -137,7 +147,11 @@ public class WebStatsGatewayImpl implements WebStatsGateway {
         if (res.getOnlineCount() != 0) {
 
             Long activeCount = personInOutService.countActive(params.getTenantId());
-            res.setActiveRate((double) activeCount / res.getOnlineCount());
+            if (activeCount == null) {
+                res.setActiveRate(null);
+            } else {
+                res.setActiveRate((double) activeCount / res.getOnlineCount());
+            }
         }
 
         res.setFallingCount(Math.toIntExact(eventListService.lambdaQuery()

+ 9 - 0
portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/mapper/PersonInOutMapper.java

@@ -3,6 +3,9 @@ package com.hfln.portal.infrastructure.mapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.hfln.portal.infrastructure.po.PersonInOutInfo;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.time.LocalDateTime;
 
 /**
  *  Mapper 接口
@@ -10,4 +13,10 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface PersonInOutMapper extends BaseMapper<PersonInOutInfo> {
 
+
+    @Select("SELECT COUNT(DISTINCT dev_id) " +
+            "FROM person_in_out_info " +
+            "WHERE tenant_id = #{tenantId} AND create_time >= #{startTime} AND create_time < #{endTime} " +
+            "GROUP BY dev_id HAVING COUNT(*) > 3")
+    Long countActive(Long tenantId, LocalDateTime startTime, LocalDateTime endTime);
 }

+ 11 - 12
portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/mqtt/handlers/PresenceChangeHandler.java

@@ -9,9 +9,7 @@ import com.hfln.portal.infrastructure.service.PersonInOutService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
-import java.time.LocalDate;
 import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
 
 @Slf4j
 @Component
@@ -55,17 +53,18 @@ public class PresenceChangeHandler extends BaseMqttHandler implements MqttMessag
         );
 
 
-        PersonInOutInfo personInOut = personInOutService.queryOneByDevId(dev.getDevId(), DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now()));
         if (presence == 1) {
-            if (personInOut == null) {
-                personInOut = new PersonInOutInfo();
-                personInOut.setTenantId(dev.getTenantId());
-                personInOut.setDevId(dev.getDevId());
-                personInOut.setCountDate(DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now()));
-                personInOut.setCount(1);
-                personInOutService.save(personInOut);
-            } else {
-                personInOut.setCount(personInOut.getCount() + 1);
+            PersonInOutInfo personInOut = new PersonInOutInfo();
+            personInOut.setTenantId(dev.getTenantId());
+            personInOut.setDevId(dev.getDevId());
+            personInOut.setEnterTime(LocalDateTime.now());
+
+            personInOutService.save(personInOut);
+        } else {
+            PersonInOutInfo personInOut = personInOutService.queryLatestOneByDevId(dev.getDevId());
+
+            if (personInOut != null && personInOut.getLeaveTime() == null) {
+                personInOut.setLeaveTime(LocalDateTime.now());
                 personInOutService.updateById(personInOut);
             }
         }

+ 6 - 5
portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/po/PersonInOutInfo.java

@@ -6,6 +6,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
+import java.time.LocalDateTime;
+
 /**
  * 人员进出表
  */
@@ -31,14 +33,13 @@ public class PersonInOutInfo extends BasePO {
     private Long devId;
 
     /**
-     * 统计日期 yyyyMMdd
+     * 进入时间
      */
-    private String countDate;
-
+    private LocalDateTime enterTime;
 
     /**
-     * 统计次数
+     * 离开时间
      */
-    private Integer count;
+    private LocalDateTime leaveTime;
 
 } 

+ 5 - 1
portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/service/PersonInOutService.java

@@ -1,11 +1,15 @@
 package com.hfln.portal.infrastructure.service;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.hfln.portal.common.request.event.WebInOutParams;
 import com.hfln.portal.infrastructure.po.PersonInOutInfo;
 
 public interface PersonInOutService extends IService<PersonInOutInfo> {
 
-    PersonInOutInfo queryOneByDevId(Long devId, String countDate);
+    PersonInOutInfo queryLatestOneByDevId(Long devId);
 
     Long countActive(Long tenantId);
+
+    Page<PersonInOutInfo> selectPage(WebInOutParams params);
 }

+ 35 - 9
portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/service/impl/PersonInOutServiceImpl.java

@@ -1,35 +1,61 @@
 package com.hfln.portal.infrastructure.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.hfln.portal.common.request.event.WebInOutParams;
 import com.hfln.portal.infrastructure.mapper.PersonInOutMapper;
 import com.hfln.portal.infrastructure.po.PersonInOutInfo;
 import com.hfln.portal.infrastructure.service.PersonInOutService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
+import java.time.LocalDateTime;
+import java.util.Objects;
 
 @Service
 @Slf4j
 public class PersonInOutServiceImpl extends ServiceImpl<PersonInOutMapper, PersonInOutInfo> implements PersonInOutService {
     @Override
-    public PersonInOutInfo queryOneByDevId(Long devId, String countDate) {
+    public PersonInOutInfo queryLatestOneByDevId(Long devId) {
 
         LambdaUpdateWrapper<PersonInOutInfo> wrapper = new LambdaUpdateWrapper<>();
         wrapper.eq(PersonInOutInfo::getDevId, devId)
-                .eq(PersonInOutInfo::getCountDate, countDate);
+                .orderByDesc(PersonInOutInfo::getCreateTime)
+                .last("limit 1");
         return this.baseMapper.selectOne(wrapper);
     }
 
     @Override
     public Long countActive(Long tenantId) {
 
-        LambdaUpdateWrapper<PersonInOutInfo> wrapper = new LambdaUpdateWrapper<>();
-        wrapper.eq(PersonInOutInfo::getTenantId, tenantId)
-                .eq(PersonInOutInfo::getCountDate, DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now()))
-                .ge(PersonInOutInfo::getCount, 3);
-        return this.baseMapper.selectCount(wrapper);
+        return this.baseMapper.countActive(tenantId, LocalDateTime.now(), LocalDateTime.now().plusDays(1));
+    }
+
+    @Override
+    public Page<PersonInOutInfo> selectPage(WebInOutParams params) {
+
+
+        Page<PersonInOutInfo> page = new Page<>(params.getPageNo(), params.getPageSize());
+
+        // 2. 构建查询条件
+        LambdaQueryWrapper<PersonInOutInfo> queryWrapper = new LambdaQueryWrapper<>();
+
+        // 3. 添加日期条件
+        if (Objects.nonNull(params.getCreateTimeStart())) {
+            queryWrapper.ge(PersonInOutInfo::getCreateTime, params.getCreateTimeStart());
+        }
+        if (Objects.nonNull(params.getCreateTimeEnd())) {
+            queryWrapper.lt(PersonInOutInfo::getCreateTime, params.getCreateTimeEnd().plusDays(1));
+        }
+
+        if (Objects.nonNull(params.getDevId())) {
+            queryWrapper.eq(PersonInOutInfo::getDevId, params.getDevId());
+        }
+
+        // 4. 设置排序
+        queryWrapper.orderByDesc(PersonInOutInfo::getCreateTime);
+        return this.baseMapper.selectPage(page, queryWrapper);
     }
 }

+ 64 - 0
portal-service-server/src/test/java/com/hfln/portal/test/service/PersonInOutServiceTest.java

@@ -0,0 +1,64 @@
+package com.hfln.portal.test.service;
+
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.context.SaTokenContext;
+import cn.dev33.satoken.spring.SaTokenContextForSpring;
+import cn.dev33.satoken.stp.StpUtil;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONWriter;
+import com.hfln.portal.infrastructure.mapper.PersonInOutMapper;
+import com.hfln.portal.infrastructure.po.PersonInOutInfo;
+import com.hfln.portal.infrastructure.service.PersonInOutService;
+import com.hfln.portal.server.Application;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class PersonInOutServiceTest {
+
+    @Before
+    public void setUp() {
+
+        // 如果是 SpringBoot 环境
+        SaTokenContext context = new SaTokenContextForSpring();
+        SaManager.setSaTokenContext(context);
+        StpUtil.login(110);
+    }
+
+    @After
+    public void clear() {
+        StpUtil.logout();
+    }
+
+
+    @Autowired
+    private PersonInOutService personInOutService;;
+
+    @Autowired
+    private PersonInOutMapper personInOutMapper;
+
+    @Test
+    @Transactional
+    public void countActive() {
+
+        Long l = personInOutService.countActive(22L);
+        System.out.println(JSON.toJSONString(l, JSONWriter.Feature.PrettyFormat));
+    }
+
+    @Test
+    @Transactional
+    public void queryLatestOneByDevId() {
+
+        PersonInOutInfo l = personInOutService.queryLatestOneByDevId(22L);
+        System.out.println(JSON.toJSONString(l, JSONWriter.Feature.PrettyFormat));
+    }
+
+}