|
@@ -0,0 +1,259 @@
|
|
|
+package com.hfln.portal.infrastructure.mqtt.handlers;
|
|
|
+
|
|
|
+import cn.hfln.framework.redis.util.RedisUtil;
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
+import com.hfln.portal.common.constant.mqtt.topic.TopicConstants;
|
|
|
+import com.hfln.portal.common.constant.redis.RedisCacheConstant;
|
|
|
+import com.hfln.portal.common.dto.data.user.SendMsgUserDto;
|
|
|
+import com.hfln.portal.domain.customer.util.MsgClient;
|
|
|
+import com.hfln.portal.domain.customer.util.WxOfficeAccountClient;
|
|
|
+import com.hfln.portal.infrastructure.mqtt.MqttClient;
|
|
|
+import com.hfln.portal.infrastructure.po.*;
|
|
|
+import com.hfln.portal.infrastructure.service.*;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Component
|
|
|
+public class FallingEventChangeHandler extends BaseMqttHandler implements MqttMessageHandler {
|
|
|
+
|
|
|
+ private final EventListService eventListService;
|
|
|
+ private final UserService userService;
|
|
|
+ private final WxRelationService wxRelationService;
|
|
|
+ private final DevShareService devShareService;
|
|
|
+ private final MqttClient mqttClient;
|
|
|
+ private final TblTenantService tblTenantService;
|
|
|
+ private final AdminUserService adminUserService;
|
|
|
+ private final RedisUtil redisUtil;
|
|
|
+ private final MsgClient msgClient;
|
|
|
+ private final WxOfficeAccountClient wxOfficeAccountClient;
|
|
|
+
|
|
|
+ private FallingEventChangeHandler(DevInfoService devInfoService,
|
|
|
+ EventListService eventListService,
|
|
|
+ WxRelationService wxRelationService,
|
|
|
+ DevShareService devShareService,
|
|
|
+ MqttClient mqttClient,
|
|
|
+ UserService userService,
|
|
|
+ TblTenantService tblTenantService,
|
|
|
+ AdminUserService adminUserService,
|
|
|
+ RedisUtil redisUtil,
|
|
|
+ MsgClient msgClient,
|
|
|
+ WxOfficeAccountClient wxOfficeAccountClient) {
|
|
|
+ super(devInfoService);
|
|
|
+ this.eventListService = eventListService;
|
|
|
+ this.wxRelationService = wxRelationService;
|
|
|
+ this.devShareService = devShareService;
|
|
|
+ this.mqttClient = mqttClient;
|
|
|
+ this.userService = userService;
|
|
|
+ this.tblTenantService = tblTenantService;
|
|
|
+ this.adminUserService = adminUserService;
|
|
|
+ this.redisUtil = redisUtil;
|
|
|
+ this.msgClient = msgClient;
|
|
|
+ this.wxOfficeAccountClient = wxOfficeAccountClient;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean supports(String action) {
|
|
|
+ return "falling_event_change".equals(action);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void handle(String topic, String payload) {
|
|
|
+
|
|
|
+ String clientId = extractDeviceId(topic);
|
|
|
+ DevInfo dev = devInfoService.queryByClientId(clientId);
|
|
|
+ if (dev == null) {
|
|
|
+ log.warn("Device not found for clientId: {}", clientId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject obj = JSONObject.parseObject(payload);
|
|
|
+ int falling = obj.getIntValue("falling");
|
|
|
+ //0:no fall 1:detected 2: confirmed 3:calling
|
|
|
+
|
|
|
+ // 2 有跌倒事件发生
|
|
|
+ if (falling == 2) {
|
|
|
+
|
|
|
+ //存储跌倒时间到数据库
|
|
|
+ EventList eventListVO = new EventList();
|
|
|
+ eventListVO.setDevId(dev.getDevId());
|
|
|
+ eventListVO.setIsHandle(0);
|
|
|
+ eventListVO.setEventType(falling);
|
|
|
+ eventListVO.setTenantId(dev.getTenantId());
|
|
|
+ eventListService.save(eventListVO);
|
|
|
+
|
|
|
+ // 整理需要接收消息的人员列表
|
|
|
+ log.info("mqttutil--有跌倒事件");
|
|
|
+ List<SendMsgUserDto> sendList = new ArrayList<>();
|
|
|
+ String devName = dev.getDevName();
|
|
|
+ Long userId = dev.getUserId();
|
|
|
+
|
|
|
+ // 需要发送提示的 有 当前设备拥有者, 被分享者, 以及 对当前设备 具有管理权限的 web管理用户
|
|
|
+ // 小程序拥有者
|
|
|
+ if (userId != null) {
|
|
|
+ UserInfo userInfo = userService.queryById(userId);
|
|
|
+ SendMsgUserDto msgUserDto = new SendMsgUserDto();
|
|
|
+ msgUserDto.setUserId(userId);
|
|
|
+ msgUserDto.setPhone(userInfo.getPhone());
|
|
|
+ msgUserDto.setUnionId(userInfo.getUnionId());
|
|
|
+ msgUserDto.setMessageFlag(true);
|
|
|
+ msgUserDto.setServiceNumberFlag(true);
|
|
|
+ WxRelation wxRelation = wxRelationService.queryOneByUnionId(userInfo.getUnionId());
|
|
|
+ if (wxRelation != null) {
|
|
|
+ msgUserDto.setFwhOpenId(wxRelation.getFwhOpenId());
|
|
|
+ }
|
|
|
+ sendList.add(msgUserDto);
|
|
|
+
|
|
|
+ // 对于 小程序拥有者,给出全局跌倒提醒,-- 被分享者是否需要
|
|
|
+ JSONObject wxMsg = new JSONObject();
|
|
|
+ wxMsg.put("clientId", clientId);
|
|
|
+ wxMsg.put("event", "fall_confirmed");
|
|
|
+ wxMsg.put("msgType", "fall");
|
|
|
+ wxMsg.put("devName", devName.toString());
|
|
|
+ wxMsg.put("eventListId", String.valueOf(eventListVO.getEventListId()));
|
|
|
+
|
|
|
+ log.info("发送微信跌倒主题消息:topic:{}, msg:{}", String.format(TopicConstants.TOPIC_MPS_NOTIC, RedisCacheConstant.WX_USER_PRE + userInfo.getUserId()), wxMsg.toString());
|
|
|
+ mqttClient.sendMessage(String.format(TopicConstants.TOPIC_MPS_NOTIC, RedisCacheConstant.WX_USER_PRE + userInfo.getUserId()), wxMsg.toString(), 2, false);
|
|
|
+
|
|
|
+ // 设备的被分享者 - 根据标志位筛选并添加到发送列表
|
|
|
+ List<DevShare> shares = devShareService.queryConfirmedByDevId(dev.getDevId());
|
|
|
+ if (!CollectionUtils.isEmpty(shares)) {
|
|
|
+ for (DevShare share : shares) {
|
|
|
+ // 发送微信跌倒主题消息
|
|
|
+ log.info("发送微信跌倒主题消息:topic:{}, msg:{}", String.format(TopicConstants.TOPIC_MPS_NOTIC, RedisCacheConstant.WX_USER_PRE + share.getSharedUserId()), wxMsg.toString());
|
|
|
+ mqttClient.sendMessage(String.format(TopicConstants.TOPIC_MPS_NOTIC, RedisCacheConstant.WX_USER_PRE + share.getSharedUserId()), wxMsg.toString(), 2, false);
|
|
|
+
|
|
|
+ // 创建被分享者的消息用户DTO
|
|
|
+ SendMsgUserDto msgUserShared = new SendMsgUserDto();
|
|
|
+ msgUserShared.setUserId(share.getSharedUserId());
|
|
|
+ msgUserShared.setPhone(share.getSharedPhone());
|
|
|
+
|
|
|
+ // 获取完整的分享信息(包含标志位)
|
|
|
+ DevShare devShare = devShareService.getById(share.getShareId());
|
|
|
+ if (devShare != null) {
|
|
|
+ // 将Integer类型的标志位转换为boolean类型:0-授权(true),1-拒绝(false)
|
|
|
+ boolean messageFlag = devShare.getMessageFlag() != null && devShare.getMessageFlag() == 0;
|
|
|
+ boolean serviceNumberFlag = devShare.getServiceNumberFlag() != null && devShare.getServiceNumberFlag() == 0;
|
|
|
+
|
|
|
+ msgUserShared.setMessageFlag(messageFlag);
|
|
|
+ msgUserShared.setServiceNumberFlag(serviceNumberFlag);
|
|
|
+
|
|
|
+ // 根据标志位决定是否添加到发送列表
|
|
|
+ // 只有当短信通知或服务号通知任一被授权时,才添加到发送列表
|
|
|
+ if (messageFlag || serviceNumberFlag) {
|
|
|
+ // 获取被分享者的微信关系信息
|
|
|
+ UserInfo sharedUserInfo = userService.queryById(share.getSharedUserId());
|
|
|
+ if (sharedUserInfo != null) {
|
|
|
+ msgUserShared.setUnionId(sharedUserInfo.getUnionId());
|
|
|
+ WxRelation sharedWxRelation = wxRelationService.queryOneByUnionId(sharedUserInfo.getUnionId());
|
|
|
+ if (sharedWxRelation != null) {
|
|
|
+ msgUserShared.setFwhOpenId(sharedWxRelation.getFwhOpenId());
|
|
|
+ }
|
|
|
+ sendList.add(msgUserShared);
|
|
|
+ log.info("被分享者已添加到发送列表: userId={}, messageFlag={}, serviceNumberFlag={}",
|
|
|
+ share.getSharedUserId(), messageFlag, serviceNumberFlag);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.info("被分享者拒绝所有通知: userId={}, messageFlag={}, serviceNumberFlag={}",
|
|
|
+ share.getSharedUserId(), messageFlag, serviceNumberFlag);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 针对跌倒事件 发送 网页 主题消息提示
|
|
|
+ String tenantName = "";
|
|
|
+ // 网页告警提示 需要当前设备绑定到租户,会发送到当前租户已经登录的管理员页面
|
|
|
+ if (dev.getTenantId() != null) {
|
|
|
+ TblTenant tblTenant = tblTenantService.getById(dev.getTenantId());
|
|
|
+ tenantName = tblTenant.getTenantName();
|
|
|
+
|
|
|
+ JSONObject webMsg = new JSONObject();
|
|
|
+ webMsg.put("clientId", clientId);
|
|
|
+ webMsg.put("event", "fall_confirmed");
|
|
|
+ webMsg.put("msgType", "fall");
|
|
|
+ webMsg.put("devName", devName.toString());
|
|
|
+ webMsg.put("tenantName", tenantName);
|
|
|
+ webMsg.put("eventListId", String.valueOf(eventListVO.getEventListId()));
|
|
|
+
|
|
|
+ // 查询当前需要发送的userId
|
|
|
+ List<AdminUserInfo> adminUserInfos = adminUserService.queryByTenantIdAndUserType(dev.getTenantId(), null);
|
|
|
+ if (!CollectionUtils.isEmpty(adminUserInfos)) {
|
|
|
+ for (AdminUserInfo adminUserInfo : adminUserInfos) {
|
|
|
+
|
|
|
+ // 判断当前用户是否登录网页
|
|
|
+ if (redisUtil.sIsMember(RedisCacheConstant.MQTT_CLIENT_USERID, RedisCacheConstant.WEB_USER_PRE + adminUserInfo.getUserId())) {
|
|
|
+ log.info("发送网页跌倒主题消息:topic:{}, msg:{}", String.format(TopicConstants.TOPIC_MPS_NOTIC, RedisCacheConstant.WEB_USER_PRE + adminUserInfo.getUserId()), webMsg.toString());
|
|
|
+ mqttClient.sendMessage(String.format(TopicConstants.TOPIC_MPS_NOTIC, RedisCacheConstant.WEB_USER_PRE + adminUserInfo.getUserId()), webMsg.toString(), 2, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //3.调用 发送短信和微信公众号通知 功能
|
|
|
+ sendMesAndWxService(sendList, devName, clientId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送短信和微信公众号通知
|
|
|
+ *
|
|
|
+ * @param sendList 需要发送通知的用户列表
|
|
|
+ * @param devName 设备名称
|
|
|
+ * @param devId 设备ID
|
|
|
+ */
|
|
|
+ private void sendMesAndWxService(List<SendMsgUserDto> sendList, String devName, String devId) {
|
|
|
+ if (CollectionUtils.isEmpty(sendList)) {
|
|
|
+ log.info("没有需要发送通知的用户");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (SendMsgUserDto sendDto : sendList) {
|
|
|
+ try {
|
|
|
+ log.info("mqttutil--开始处理用户通知: userId={}, messageFlag={}, serviceNumberFlag={}",
|
|
|
+ sendDto.getUserId(), sendDto.isMessageFlag(), sendDto.isServiceNumberFlag());
|
|
|
+
|
|
|
+ // 根据短信标志位决定是否发送短信
|
|
|
+ if (sendDto.isMessageFlag()) {
|
|
|
+ try {
|
|
|
+ log.info("mqttutil--开始发送跌倒短信: phone={}, dev_name={}", sendDto.getPhone(), devName);
|
|
|
+ msgClient.sendNotifyMsg(sendDto.getPhone(), devName);
|
|
|
+ log.info("mqttUtil--短信发送完成");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("发送短信失败: userId={}, phone={}, error={}",
|
|
|
+ sendDto.getUserId(), sendDto.getPhone(), e.getMessage(), e);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.info("用户拒绝短信通知: userId={}", sendDto.getUserId());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据服务号标志位决定是否发送微信公众号消息
|
|
|
+ if (sendDto.isServiceNumberFlag() && StringUtils.isNotBlank(sendDto.getFwhOpenId())) {
|
|
|
+ try {
|
|
|
+ log.info("发送微信公众号信息:devName={}, phoneNo={}, fwhOpenId={}",
|
|
|
+ devName, sendDto.getPhone(), sendDto.getFwhOpenId());
|
|
|
+ // 发送微信公众号消息
|
|
|
+ wxOfficeAccountClient.sendMsg(devId, devName, sendDto.getPhone(),
|
|
|
+ sendDto.getFwhOpenId(), "设备检测到跌倒,请前往小程序查看详细信息");
|
|
|
+ log.info("微信公众号消息发送完成");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("发送微信公众号消息失败: userId={}, fwhOpenId={}, error={}",
|
|
|
+ sendDto.getUserId(), sendDto.getFwhOpenId(), e.getMessage(), e);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.info("用户拒绝服务号通知或未绑定微信: userId={}, serviceNumberFlag={}, fwhOpenId={}",
|
|
|
+ sendDto.getUserId(), sendDto.isServiceNumberFlag(), sendDto.getFwhOpenId());
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("处理用户通知异常: userId={}, error={}",
|
|
|
+ sendDto.getUserId(), e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|