浏览代码

1.完成查看用户对设备的服务权限接口
2.调整小程序处理跌倒事件接口
3.完成用户查询10分钟内拥有设备的跌倒事件

hxd 2 月之前
父节点
当前提交
c9f96863bc

+ 3 - 6
portal-service-application/src/main/java/com/hfln/portal/application/controller/wap/EventController.java

@@ -7,10 +7,7 @@ import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 @Slf4j
 @RestController
@@ -23,9 +20,9 @@ public class EventController {
     private DeviceGateway deviceGateway;
 
 
-    @GetMapping("/handleEvent/{eventListId}")
+    @GetMapping("/handleEvent")
     @Operation(summary = "小程序处理设备跌倒事件")
-    public ApiResult<Boolean> handleEvent(@PathVariable("eventListId") Long eventListId){
+    public ApiResult<Boolean> handleEvent(@RequestParam Long eventListId){
         return ApiResult.success(deviceGateway.handleEvent(eventListId));
     }
 

+ 9 - 4
portal-service-application/src/main/java/com/hfln/portal/application/controller/wap/StatsController.java

@@ -4,6 +4,7 @@ package com.hfln.portal.application.controller.wap;
 import cn.hfln.framework.catchlog.CatchAndLog;
 import cn.hfln.framework.dto.ApiResult;
 import com.hfln.portal.common.dto.data.event.AlarmEventDTO;
+import com.hfln.portal.common.dto.data.event.EventListDTO;
 import com.hfln.portal.common.request.event.AlarmEventParams;
 import com.hfln.portal.common.vo.PageRecord;
 import com.hfln.portal.domain.gateway.StatsGateway;
@@ -11,12 +12,10 @@ import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
+import java.util.List;
 
 @Slf4j
 @RestController
@@ -33,4 +32,10 @@ public class StatsController {
     public ApiResult<PageRecord<AlarmEventDTO>> alarmRetentionQuery(@Valid @RequestBody AlarmEventParams params) {
         return ApiResult.success(statsGateway.alarmRetentionQuery(params));
     }
+
+    @GetMapping("/fallingEventsQuery")
+    @Operation(summary = "跌倒事件查询")
+    public ApiResult<List<EventListDTO>> fallingEventsQuery(@RequestParam("user_id") Long userId) {
+        return ApiResult.success(statsGateway.fallingEventsQuery(userId));
+    }
 }

+ 6 - 0
portal-service-common/src/main/java/com/hfln/portal/common/constant/redis/RedisCacheConstant.java

@@ -35,4 +35,10 @@ public interface RedisCacheConstant {
      * mqtt客户端缓存
      */
     String MQTT_CLIENT_USERID = "mqtt:client:userId";
+
+    /**
+     * 跌倒事件弹窗缓存
+     */
+    String FALLING_EVENTS_KEY_PRE = "hfln:events";
+
 }

+ 1 - 1
portal-service-common/src/main/java/com/hfln/portal/common/request/share/QueryUserVoipParam.java

@@ -19,5 +19,5 @@ public class QueryUserVoipParam extends BaseVO {
 
     @Schema(description = "设备ID")
     @NotNull
-    private Long devId;
+    private String clientId;
 }

+ 4 - 0
portal-service-domain/src/main/java/com/hfln/portal/domain/exception/ErrorEnum.java

@@ -128,6 +128,10 @@ public enum ErrorEnum implements ErrorEnumInterface{
      */
     TENANT_IS_ALREADY_EXIST("13001", "租户已经存在!"),
 
+    /**
+     * 事件相关
+     */
+    FALLING_EVENT_NOT_EXIST("14001", "跌倒事件不存在!")
     ;
 
     private final String errorCode;

+ 6 - 0
portal-service-domain/src/main/java/com/hfln/portal/domain/gateway/StatsGateway.java

@@ -1,10 +1,16 @@
 package com.hfln.portal.domain.gateway;
 
 import com.hfln.portal.common.dto.data.event.AlarmEventDTO;
+import com.hfln.portal.common.dto.data.event.EventListDTO;
 import com.hfln.portal.common.request.event.AlarmEventParams;
 import com.hfln.portal.common.vo.PageRecord;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.List;
 
 public interface StatsGateway {
 
     PageRecord<AlarmEventDTO> alarmRetentionQuery(AlarmEventParams params);
+
+    List<EventListDTO> fallingEventsQuery(@RequestParam("user_id") Long userId);
 }

+ 64 - 10
portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/gateway/impl/DeviceGatewayImpl.java

@@ -11,6 +11,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.hfln.portal.common.constant.UserConstants;
 import com.hfln.portal.common.constant.mqtt.topic.TopicConstants;
+import com.hfln.portal.common.constant.redis.RedisCacheConstant;
 import com.hfln.portal.common.dto.data.device.DeviceDTO;
 import com.hfln.portal.common.dto.data.event.EventListDTO;
 import com.hfln.portal.common.dto.data.event.StayTimeDTO;
@@ -53,10 +54,12 @@ import org.springframework.web.multipart.MultipartFile;
 import java.io.IOException;
 import java.io.InputStream;
 import java.math.BigDecimal;
+import java.time.Duration;
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -76,7 +79,7 @@ public class DeviceGatewayImpl implements DeviceGateway {
     private DevGroupService devGroupService;
 
     @Autowired
-    private EventService eventService;
+    private EventListService eventListService;
 
     @Autowired
     private OssFileService ossFileService;
@@ -374,14 +377,48 @@ public class DeviceGatewayImpl implements DeviceGateway {
 
     @Override
     public Boolean handleEvent(Long eventListId) {
-        //获取当前操作者手机号
-        String phone = (String) StpUtil.getSession().get(UserConstants.SA_USER_PHONE);
-
-        LambdaUpdateWrapper<EventList> updateWrapper = new LambdaUpdateWrapper<>();
-        updateWrapper.eq(EventList::getEventListId, eventListId)
-                .set(EventList::getIsHandle, 1)
-                .set(EventList::getRemark, PhoneUtils.maskPhone(phone));
-        return this.eventService.update(updateWrapper);
+
+        //1.查询事件信息
+        EventList eventList = eventListService.getById(eventListId);
+        if (eventList == null){
+            throw new BizException(ErrorEnum.FALLING_EVENT_NOT_EXIST.getErrorCode(), ErrorEnum.FALLING_EVENT_NOT_EXIST.getErrorMessage());
+        }
+
+        // 2.构建 Redis key  和 当前处理人
+        String redisKey = RedisCacheConstant.FALLING_EVENTS_KEY_PRE + ":" + eventListId;
+        String userId = String.valueOf(StpUtil.getSession().get(UserConstants.SA_USER_ID));
+
+        // 3.如果事件未处理
+        if(eventList.getIsHandle() == 0) {
+            // 获取当前处理者手机号
+            String phone = String.valueOf(StpUtil.getSession().get(UserConstants.SA_USER_PHONE));
+
+            LambdaUpdateWrapper<EventList> updateWrapper = new LambdaUpdateWrapper<>();
+            updateWrapper.eq(EventList::getEventListId, eventListId)
+                    .set(EventList::getIsHandle, 1)
+                    .set(EventList::getRemark, PhoneUtils.maskPhone(phone));
+
+            // 存入 Redis Set
+            redisTemplate.opsForSet().add(redisKey, userId);
+
+            // 计算 TTL 并设置过期时间
+            LocalDateTime createTime = eventList.getCreateTime();  // 事件发生时间
+            LocalDateTime now = LocalDateTime.now();  // 接口调用时间
+            long ttlSeconds = Duration.between(now, createTime.plusSeconds(600)).getSeconds();   //剩余时间
+
+            if(ttlSeconds > 0){
+                redisTemplate.expire(redisKey, ttlSeconds, TimeUnit.SECONDS);
+            } else {
+                // 已超时 直接删除key
+                redisTemplate.delete(redisKey);
+            }
+
+            return this.eventListService.update(updateWrapper);
+        }
+
+        // 4.如果事件已处理
+        redisTemplate.opsForSet().add(redisKey, userId);
+        return true;
     }
 
 //    @Override
@@ -839,10 +876,27 @@ public class DeviceGatewayImpl implements DeviceGateway {
 
     @Override
     public QueryUserPermissionDTO queryUserPermission(QueryUserVoipParam param){
+        // 1.根据设备id查询设备信息
+        DevInfo devInfo = devInfoService.queryOneByClientId(param.getClientId());
+        if (devInfo == null) {
+            throw new BizException(ErrorEnum.DEVICE_IS_NOT_EXIST.getErrorCode(), ErrorEnum.DEVICE_IS_NOT_EXIST.getErrorMessage());
+        }
+
+        // 2.校验用户是否为主绑人
+        if (devInfo.getUserId().equals(param.getUserId())) {
+            QueryUserPermissionDTO DTO = new QueryUserPermissionDTO();
+            DTO.setMessageFlag(0);
+            DTO.setServiceNumberFlag(0);
+            DTO.setVoipFlag(0);
+            return DTO;
+        }
+
+        // 3.用户不为主绑人,则查询分享记录获取权限
         LambdaQueryWrapper<DevShare> queryWrapper = new LambdaQueryWrapper<>();
-        queryWrapper.eq(DevShare::getDevId, param.getDevId());
+        queryWrapper.eq(DevShare::getDevId, devInfo.getDevId());
         queryWrapper.eq(DevShare::getSharedUserId, param.getUserId());
         queryWrapper.eq(DevShare::getState, DevShare.Constants.ShareStatus.SHARED);
+        queryWrapper.eq(DevShare::getIsDeleted, BasePO.DeleteFlag.NOT_DELETED);
         DevShare devShare = devShareService.getOne(queryWrapper);
 
         if (devShare == null){

+ 50 - 0
portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/gateway/impl/StatsGatewayImpl.java

@@ -3,7 +3,9 @@ package com.hfln.portal.infrastructure.gateway.impl;
 import cn.dev33.satoken.stp.StpUtil;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.hfln.portal.common.constant.UserConstants;
+import com.hfln.portal.common.constant.redis.RedisCacheConstant;
 import com.hfln.portal.common.dto.data.event.AlarmEventDTO;
+import com.hfln.portal.common.dto.data.event.EventListDTO;
 import com.hfln.portal.common.request.event.AlarmEventParams;
 import com.hfln.portal.common.vo.PageRecord;
 import com.hfln.portal.domain.customer.util.CopyUtils;
@@ -13,6 +15,7 @@ import com.hfln.portal.infrastructure.po.DevInfo;
 import com.hfln.portal.infrastructure.service.AlarmEventService;
 import com.hfln.portal.infrastructure.service.DevInfoService;
 import com.hfln.portal.infrastructure.service.DevShareService;
+import com.hfln.portal.infrastructure.service.EventListService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -38,6 +41,12 @@ public class StatsGatewayImpl implements StatsGateway {
     @Autowired
     private AlarmEventService alarmEventService;
 
+    @Autowired
+    private EventListService eventListService;
+
+    @Autowired
+    private org.springframework.data.redis.core.RedisTemplate<String, Object> redisTemplate;
+
     @Override
     public PageRecord<AlarmEventDTO> alarmRetentionQuery(AlarmEventParams params) {
         // 1.从会话中获取当前用户的id
@@ -83,4 +92,45 @@ public class StatsGatewayImpl implements StatsGateway {
         // 封装成 PageRecord 返回
         return CopyUtils.copyPage(page, dtoList);
     }
+
+
+    @Override
+    public List<EventListDTO> fallingEventsQuery(Long userId) {
+
+        // 1.根据userId获取用户自己设备与被分享设备的id集合
+            // 1.1 获取用户被分享的设备id集合  sharedDevIds
+        Optional<List<Long>> sharedDevIds = devShareService.queryDeviceIdByUserId(userId);
+        log.info("用户被分享的设备id集合: {}", sharedDevIds);
+
+            // 1.2 获取用户自己设备的id集合    devIds
+        List<Long> devIds = devInfoService.queryByUserId(userId);
+        log.info("用户自己设备的id集合: {}", devIds);
+
+            // 1.3 合并devIds和sharedDevIds
+        List<Long> allDevIds = Stream.concat(
+                        Optional.ofNullable(devIds).orElseGet(Collections::emptyList).stream(),
+                        sharedDevIds.orElseGet(Collections::emptyList).stream()
+                ).distinct()  //去重 + 顺序
+                .collect(Collectors.toList());
+        log.info("用户设备id集合: {}", allDevIds);
+
+
+        if (allDevIds.isEmpty()){
+            return Collections.emptyList();
+        }
+
+        //2. 查询当前用户下设备的最近10分钟内发生跌倒事件且未处理的事件
+        List<EventListDTO> events = eventListService.queryFallingEvents(allDevIds);
+        List<EventListDTO> filteredEvents = events.stream()
+                .filter(event -> {
+                    String redisKey = RedisCacheConstant.FALLING_EVENTS_KEY_PRE + ":" + event.getEventListId();
+                    // 判断 Redis Set 中是否存在当前用户
+                    Boolean hasUser = redisTemplate.opsForSet().isMember(redisKey, userId.toString());
+                    return !Boolean.TRUE.equals(hasUser);  // 如果不存在 userId,则保留
+                })
+                .collect(Collectors.toList());
+        log.info("用户 {} 查询到最近10分钟内未处理的跌倒事件数量: {}", userId, filteredEvents.size());
+
+        return filteredEvents;
+    }
 }

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

@@ -42,7 +42,7 @@ public class WebStatsGatewayImpl implements WebStatsGateway {
     private DevInfoService devInfoService;
 
     @Autowired
-    private EventService eventService;
+    private EventListService eventListService;
 
     @Autowired
     private StayTimeService stayTimeService;
@@ -70,7 +70,7 @@ public class WebStatsGatewayImpl implements WebStatsGateway {
         // 如果tenantId为0或null,则不添加设备ID查询条件,查询所有事件(超管权限)
 
         //调用返回Page<EventList>
-        Page<EventList> page = eventService.queryEventList(params, devIdList);
+        Page<EventList> page = eventListService.queryEventList(params, devIdList);
 
         //转化为DTO
         List<EventListDTO> dtoList = CopyUtils.copyList(page.getRecords(), EventListDTO.class);

+ 2 - 2
portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/mqtt/MqttSubHandle.java

@@ -38,7 +38,7 @@ public class MqttSubHandle {
     private DevInfoService devInfoService;
 
     @Autowired
-    private EventService eventService;
+    private EventListService eventListService;
 
     @Autowired
     private UserService userService;
@@ -164,7 +164,7 @@ public class MqttSubHandle {
             eventListVO.setIsHandle(0);
             eventListVO.setTargetPoints(targetPointsStr);
             eventListVO.setEventType((int) messageType);
-            eventService.save(eventListVO);
+            eventListService.save(eventListVO);
 
 
             //  向前端发送数据

+ 4 - 1
portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/service/EventService.java → portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/service/EventListService.java

@@ -2,12 +2,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.dto.data.event.EventListDTO;
 import com.hfln.portal.common.request.event.EventListParams;
 import com.hfln.portal.infrastructure.po.EventList;
 
 import java.util.List;
 
-public interface EventService extends IService<EventList> {
+public interface EventListService extends IService<EventList> {
 
     Page<EventList> queryEventList(EventListParams params, List<Long> devIdList);
+
+    List<EventListDTO> queryFallingEvents(List<Long> devIdList);
 }

+ 29 - 2
portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/service/impl/EventServiceImpl.java → portal-service-infrastructure/src/main/java/com/hfln/portal/infrastructure/service/impl/EventListServiceImpl.java

@@ -3,17 +3,22 @@ package com.hfln.portal.infrastructure.service.impl;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.hfln.portal.common.dto.data.event.EventListDTO;
 import com.hfln.portal.common.request.event.EventListParams;
 import com.hfln.portal.infrastructure.mapper.EventListMapper;
 import com.hfln.portal.infrastructure.po.EventList;
-import com.hfln.portal.infrastructure.service.EventService;
+import com.hfln.portal.infrastructure.service.EventListService;
+import org.springframework.beans.BeanUtils;
 import org.springframework.stereotype.Service;
 
+import java.time.LocalDateTime;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 @Service
-public class EventServiceImpl extends ServiceImpl<EventListMapper, EventList> implements EventService {
+public class EventListServiceImpl extends ServiceImpl<EventListMapper, EventList> implements EventListService {
     @Override
     public Page<EventList> queryEventList(EventListParams params, List<Long> devIdList) {
         Page<EventList> page = new Page<>(params.getPageNo(), params.getPageSize());
@@ -41,4 +46,26 @@ public class EventServiceImpl extends ServiceImpl<EventListMapper, EventList> im
         queryWrapper.orderByDesc(EventList::getCreateTime);
         return this.baseMapper.selectPage(page, queryWrapper);
     }
+
+    @Override
+    public List<EventListDTO> queryFallingEvents(List<Long> devIdList) {
+        LambdaQueryWrapper<EventList> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.in(EventList::getDevId, devIdList)
+                .ge(EventList::getCreateTime, LocalDateTime.now().minusMinutes(10));  //最近10分钟内
+
+        // 执行查询
+        List<EventList> list = this.list(queryWrapper);
+
+        if (list == null || list.isEmpty()){
+            return Collections.emptyList();
+        }
+
+        return list.stream()
+                .map(event -> {
+                    EventListDTO dto = new EventListDTO();
+                    BeanUtils.copyProperties(event, dto);
+                    return dto;
+                })
+                .collect(Collectors.toList());
+    }
 }