Merge branch 'dyf-device' into 6170

This commit is contained in:
2025-09-16 17:05:19 +08:00
30 changed files with 438 additions and 49 deletions

View File

@ -3,6 +3,7 @@ package com.fuyuanshen.global.mqtt.config;
import cn.hutool.core.lang.UUID; import cn.hutool.core.lang.UUID;
import com.fuyuanshen.global.mqtt.receiver.ReceiverMessageHandler; import com.fuyuanshen.global.mqtt.receiver.ReceiverMessageHandler;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -55,4 +56,10 @@ public class MqttInboundConfiguration {
public MessageHandler messageHandler(){ public MessageHandler messageHandler(){
return receiverMessageHandler; return receiverMessageHandler;
} }
// @Bean
// @ServiceActivator(inputChannel = "messageInboundChannel") // 确保通道名称正确
// public MessageHandler deviceAlarmMessageHandler() {
// return new DeviceAlrmMessageHandler();
// }
} }

View File

@ -1,8 +1,18 @@
package com.fuyuanshen.global.mqtt.rule.bjq; package com.fuyuanshen.global.mqtt.rule.bjq;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSONObject;
import com.fuyuanshen.common.core.constant.GlobalConstants; import com.fuyuanshen.common.core.constant.GlobalConstants;
import com.fuyuanshen.common.core.domain.model.LoginUser;
import com.fuyuanshen.common.core.utils.StringUtils; import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.core.utils.date.DurationUtils;
import com.fuyuanshen.common.redis.utils.RedisUtils; import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.common.satoken.utils.LoginHelper;
import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.bo.DeviceAlarmBo;
import com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo;
import com.fuyuanshen.equipment.service.DeviceService;
import com.fuyuanshen.equipment.service.IDeviceAlarmService;
import com.fuyuanshen.global.mqtt.base.MqttMessageRule; import com.fuyuanshen.global.mqtt.base.MqttMessageRule;
import com.fuyuanshen.global.mqtt.base.MqttRuleContext; import com.fuyuanshen.global.mqtt.base.MqttRuleContext;
import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
@ -13,9 +23,11 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.Duration; import java.time.Duration;
import java.util.Date;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY; import static com.fuyuanshen.common.core.constant.GlobalConstants.FUNCTION_ACCESS_KEY;
import static com.fuyuanshen.common.core.constant.GlobalConstants.GLOBAL_REDIS_KEY;
import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*; import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*;
/** /**
@ -26,6 +38,11 @@ import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.*;
@Slf4j @Slf4j
public class BjqAlarmRule implements MqttMessageRule { public class BjqAlarmRule implements MqttMessageRule {
private final IDeviceAlarmService deviceAlarmService;
private final DeviceService deviceService;
@Override @Override
public String getCommandType() { public String getCommandType() {
return LightingCommandTypeConstants.ALARM_MESSAGE; return LightingCommandTypeConstants.ALARM_MESSAGE;
@ -38,14 +55,21 @@ public class BjqAlarmRule implements MqttMessageRule {
Object[] convertArr = context.getConvertArr(); Object[] convertArr = context.getConvertArr();
String convertValue = convertArr[1].toString(); String convertValue = convertArr[1].toString();
if(StringUtils.isNotBlank(convertValue)){ if (StringUtils.isNotBlank(convertValue)) {
// 将设备状态信息存储到Redis中 // 将设备状态信息存储到Redis中
String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY+DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX; String deviceRedisKey = GlobalConstants.GLOBAL_REDIS_KEY + DeviceRedisKeyConstants.DEVICE_KEY_PREFIX + context.getDeviceImei() + DEVICE_ALARM_KEY_PREFIX;
// 存储到Redis // 存储到Redis
RedisUtils.setCacheObject(deviceRedisKey, convertValue); RedisUtils.setCacheObject(deviceRedisKey, convertValue);
} }
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20)); RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20));
// 保存告警信息
String deviceImei = context.getDeviceImei();
// 设备告警状态 0:解除告警 1:报警产生
Byte state = (Byte) convertArr[1];
savaAlarm(deviceImei, state);
} catch (Exception e) { } catch (Exception e) {
log.error("处理告警命令时出错", e); log.error("处理告警命令时出错", e);
RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20)); RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.FAILED.getCode(), Duration.ofSeconds(20));
@ -53,4 +77,49 @@ public class BjqAlarmRule implements MqttMessageRule {
} }
public void savaAlarm(String deviceImei, Byte state) {
DeviceAlarmVo deviceAlarmVo = deviceAlarmService.queryLatestByDeviceImei(deviceImei);
DeviceAlarmBo deviceAlarmBo = new DeviceAlarmBo();
// 解除告警
if (state == 0) {
if (deviceAlarmVo != null) {
if (deviceAlarmVo.getFinishTime() == null) {
BeanUtil.copyProperties(deviceAlarmVo, deviceAlarmBo);
deviceAlarmBo.setFinishTime(new Date());
String durationBetween = DurationUtils.getDurationBetween(deviceAlarmVo.getStartTime(), deviceAlarmBo.getFinishTime());
deviceAlarmBo.setDurationTime(durationBetween);
deviceAlarmService.updateByBo(deviceAlarmBo);
}
}
}
// 报警产生
if (state == 1) {
if (deviceAlarmVo == null || deviceAlarmVo.getFinishTime() != null) {
Device device = deviceService.selectDeviceByImei(deviceImei);
deviceAlarmBo.setDeviceId(device.getId());
deviceAlarmBo.setDeviceImei(deviceImei);
// 0-强制报警1-撞击闯入2-自动报警3-电子围栏告警
deviceAlarmBo.setDeviceAction(0);
deviceAlarmBo.setStartTime(new Date());
// 0已处理1未处理
deviceAlarmBo.setTreatmentState(1);
// LoginUser loginUser = LoginHelper.getLoginUser();
// deviceAlarmBo.setCreateBy(loginUser.getUserId());
deviceAlarmBo.setTenantId(device.getTenantId());
String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX);
if (StringUtils.isNotBlank(location)) {
JSONObject jsonObject = JSONObject.parseObject(location);
deviceAlarmBo.setLocation(jsonObject.getString("address"));
}
deviceAlarmService.insertByBo(deviceAlarmBo);
}
}
}
} }

View File

@ -47,6 +47,7 @@ public class DeviceFenceAccessRecordController extends BaseController {
return deviceFenceAccessRecordService.queryPageList(bo, pageQuery); return deviceFenceAccessRecordService.queryPageList(bo, pageQuery);
} }
/** /**
* 导出围栏进出记录列表 * 导出围栏进出记录列表
*/ */

View File

@ -50,6 +50,7 @@ public class DeviceGeoFenceController extends BaseController {
return deviceGeoFenceService.queryPageList(bo, pageQuery); return deviceGeoFenceService.queryPageList(bo, pageQuery);
} }
/** /**
* 导出电子围栏列表 * 导出电子围栏列表
*/ */

View File

@ -0,0 +1,85 @@
// package com.fuyuanshen.web.handler.mqtt;
//
// import cn.hutool.core.lang.Dict;
// import com.fuyuanshen.common.core.constant.GlobalConstants;
// import com.fuyuanshen.common.json.utils.JsonUtils;
// import com.fuyuanshen.common.redis.utils.RedisUtils;
// import com.fuyuanshen.global.mqtt.base.MqttRuleContext;
// import com.fuyuanshen.global.mqtt.base.MqttRuleEngine;
// import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants;
// import lombok.extern.slf4j.Slf4j;
// import org.apache.commons.lang3.StringUtils;
// import org.springframework.beans.factory.annotation.Autowired;
// import org.springframework.messaging.Message;
// import org.springframework.messaging.MessageHandler;
// import org.springframework.messaging.MessageHeaders;
// import org.springframework.messaging.MessagingException;
// import org.springframework.stereotype.Service;
//
// import java.time.Duration;
// import java.util.Objects;
//
// import static com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants.DEVICE_KEY_PREFIX;
//
// /**
// * @author: 默苍璃
// * @date: 2025-09-1609:28
// */
// @Service
// @Slf4j
// public class DeviceAlrmMessageHandler implements MessageHandler {
//
// @Autowired
// private MqttRuleEngine ruleEngine;
//
// @Override
// public void handleMessage(Message<?> message) throws MessagingException {
//
// // 处理新类型的消息
// Object payload = message.getPayload();
// MessageHeaders headers = message.getHeaders();
// String receivedTopic = Objects.requireNonNull(headers.get("mqtt_receivedTopic")).toString();
//
// log.info("设备强制报警消息处理器 - MQTT payload= {} \n receivedTopic = {}", payload, receivedTopic);
//
// // 解析消息并执行相应逻辑
// Dict payloadDict = JsonUtils.parseMap(payload.toString());
// if (payloadDict != null) {
// // 根据主题或消息内容执行不同的处理逻辑
// processMessage(receivedTopic, payloadDict);
// }
// }
//
// private void processMessage(String topic, Dict payloadDict) {
// // 实现具体的业务逻辑
// // 可以根据不同的主题执行不同的操作
// if (topic.contains("newTopic")) {
// // 处理特定主题的消息
// handleNewTopicMessage(payloadDict);
// }
// }
//
// private void handleNewTopicMessage(Dict payloadDict) {
// // 实现新主题消息的具体处理逻辑
// String deviceImei = payloadDict.getStr("imei");
// if (StringUtils.isNotBlank(deviceImei)) {
// // 更新设备状态到Redis
// String deviceOnlineStatusRedisKey = GlobalConstants.GLOBAL_REDIS_KEY +
// DEVICE_KEY_PREFIX + deviceImei + DeviceRedisKeyConstants.DEVICE_ONLINE_STATUS_KEY_PREFIX;
// RedisUtils.setCacheObject(deviceOnlineStatusRedisKey, "1", Duration.ofSeconds(62));
//
// // 执行规则引擎
// MqttRuleContext context = new MqttRuleContext();
// context.setDeviceImei(deviceImei);
// context.setPayloadDict(payloadDict);
// // 设置命令类型
// context.setCommandType((byte) 0x02); // 根据实际需要设置命令类型
//
// boolean ruleExecuted = ruleEngine.executeRule(context);
// if (!ruleExecuted) {
// log.warn("未找到匹配的规则来处理新主题消息设备IMEI: {}", deviceImei);
// }
// }
// }
// }
//

View File

@ -301,8 +301,8 @@ file:
mqtt: mqtt:
username: admin username: admin
password: #YtvpSfCNG password: #YtvpSfCNG
url: tcp://47.120.79.150:2883 url: tcp://47.120.79.150:3883
subClientId: fys_subClient subClientId: fys_subClient
subTopic: worker/location/# subTopic: A/#
pubTopic: B/# pubTopic: B/#
pubClientId: fys_pubClient pubClientId: fys_pubClient

View File

@ -0,0 +1,108 @@
package com.fuyuanshen.common.core.utils.date;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* 持续时间工具类
* 提供计算两个日期之间差值的方法,并以时分秒格式返回
*
* @author fys
*/
public class DurationUtils {
/**
* 计算两个日期之间的差值,返回时分秒格式的字符串
* 格式为 "X小时 Y分钟 Z秒"
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 时分秒格式的时间差字符串
*/
public static String getDurationBetween(Date startDate, Date endDate) {
if (startDate == null || endDate == null) {
return "0小时 0分钟 0秒";
}
long diffInMillis = Math.abs(endDate.getTime() - startDate.getTime());
long hours = TimeUnit.MILLISECONDS.toHours(diffInMillis);
long minutes = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
long seconds = TimeUnit.MILLISECONDS.toSeconds(diffInMillis) % 60;
return String.format("%d小时 %d分钟 %d秒", hours, minutes, seconds);
}
/**
* 计算两个日期之间的差值,返回时分秒格式的字符串
* 仅显示非零单位
*
* @param startDate 开始日期
* @param endDate 结束日期
* @return 时分秒格式的时间差字符串,仅显示非零单位
*/
public static String getDurationBetweenPretty(Date startDate, Date endDate) {
if (startDate == null || endDate == null) {
return "0秒";
}
long diffInMillis = Math.abs(endDate.getTime() - startDate.getTime());
long hours = TimeUnit.MILLISECONDS.toHours(diffInMillis);
long minutes = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
long seconds = TimeUnit.MILLISECONDS.toSeconds(diffInMillis) % 60;
StringBuilder result = new StringBuilder();
if (hours > 0) {
result.append(hours).append("小时 ");
}
if (minutes > 0) {
result.append(minutes).append("分钟 ");
}
if (seconds > 0 || result.length() == 0) {
result.append(seconds).append("");
}
return result.toString().trim();
}
/**
* 计算指定毫秒数的持续时间,返回时分秒格式的字符串
*
* @param millis 毫秒数
* @return 时分秒格式的持续时间字符串
*/
public static String getDurationFromMillis(long millis) {
long absMillis = Math.abs(millis);
long hours = TimeUnit.MILLISECONDS.toHours(absMillis);
long minutes = TimeUnit.MILLISECONDS.toMinutes(absMillis) % 60;
long seconds = TimeUnit.MILLISECONDS.toSeconds(absMillis) % 60;
return String.format("%d小时 %d分钟 %d秒", hours, minutes, seconds);
}
/**
* 计算指定毫秒数的持续时间,返回时分秒格式的字符串
* 仅显示非零单位
*
* @param millis 毫秒数
* @return 时分秒格式的持续时间字符串,仅显示非零单位
*/
public static String getDurationFromMillisPretty(long millis) {
long absMillis = Math.abs(millis);
long hours = TimeUnit.MILLISECONDS.toHours(absMillis);
long minutes = TimeUnit.MILLISECONDS.toMinutes(absMillis) % 60;
long seconds = TimeUnit.MILLISECONDS.toSeconds(absMillis) % 60;
StringBuilder result = new StringBuilder();
if (hours > 0) {
result.append(hours).append("小时 ");
}
if (minutes > 0) {
result.append(minutes).append("分钟 ");
}
if (seconds > 0 || result.length() == 0) {
result.append(seconds).append("");
}
return result.toString().trim();
}
}

View File

@ -2,6 +2,8 @@ package com.fuyuanshen.equipment.domain;
import com.fuyuanshen.common.tenant.core.TenantEntity; import com.fuyuanshen.common.tenant.core.TenantEntity;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
import io.github.linpeilie.annotations.AutoMapping;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -100,4 +102,12 @@ public class DeviceAlarm extends TenantEntity {
private Long treatmentState; private Long treatmentState;
/**
* 设备IMEI
* device_imei
*/
@Schema(title = "设备IMEI")
@AutoMapping(target = "deviceImei")
private String deviceImei;
} }

View File

@ -52,12 +52,12 @@ public class DeviceFenceAccessRecord extends BaseEntity {
/** /**
* 纬度 * 纬度
*/ */
private Long latitude; private Double latitude;
/** /**
* 经度 * 经度
*/ */
private Long longitude; private Double longitude;
/** /**
* 定位精度 * 定位精度

View File

@ -59,8 +59,8 @@ public class DeviceType extends TenantEntity {
@Schema(title = "联网方式", example = "0:无;1:4G;2:WIFI") @Schema(title = "联网方式", example = "0:无;1:4G;2:WIFI")
private String networkWay; private String networkWay;
@Schema(title = "通讯方式", example = "0:4G;1:蓝牙,2 4G&蓝牙") @Schema(title = "通讯方式", example = "通讯方式 0:4G;1:蓝牙,2 4G&蓝牙")
private String communicationMode; private Integer communicationMode;
/** /**
* 创建人名称 * 创建人名称

View File

@ -2,6 +2,7 @@ package com.fuyuanshen.equipment.domain.bo;
import com.fuyuanshen.common.core.validate.EditGroup; import com.fuyuanshen.common.core.validate.EditGroup;
import com.fuyuanshen.common.mybatis.core.domain.BaseEntity; import com.fuyuanshen.common.mybatis.core.domain.BaseEntity;
import com.fuyuanshen.common.tenant.core.TenantEntity;
import com.fuyuanshen.equipment.domain.DeviceAlarm; import com.fuyuanshen.equipment.domain.DeviceAlarm;
import io.github.linpeilie.annotations.AutoMapper; import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
@ -19,7 +20,7 @@ import java.util.Date;
@Data @Data
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@AutoMapper(target = DeviceAlarm.class, reverseConvertGenerate = false) @AutoMapper(target = DeviceAlarm.class, reverseConvertGenerate = false)
public class DeviceAlarmBo extends BaseEntity { public class DeviceAlarmBo extends TenantEntity {
/** /**
* ID * ID
@ -35,6 +36,7 @@ public class DeviceAlarmBo extends BaseEntity {
/** /**
* 报警事项 * 报警事项
* device_action * device_action
* 0-强制报警1-撞击闯入2-自动报警3-电子围栏告警
*/ */
private Integer deviceAction; private Integer deviceAction;
@ -99,7 +101,7 @@ public class DeviceAlarmBo extends BaseEntity {
/** /**
* 报警持续时间 * 报警持续时间
*/ */
private Long durationTime; private String durationTime;
/** /**
* 报警查询时间 * 报警查询时间

View File

@ -74,6 +74,16 @@ public class DeviceFenceAccessRecordBo extends BaseEntity {
@NotNull(message = "事件时间不能为空", groups = { AddGroup.class, EditGroup.class }) @NotNull(message = "事件时间不能为空", groups = { AddGroup.class, EditGroup.class })
private Date eventTime; private Date eventTime;
/**
* 开始时间
*/
private String beginTime;
/**
* 结束时间
*/
private String endTime;
/** /**
* 记录创建时间 * 记录创建时间
*/ */

View File

@ -23,7 +23,7 @@ public class AppDeviceBo {
private String deviceMac; private String deviceMac;
/** /**
* 通讯方式 0:4G; 1:蓝牙 * 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
*/ */
@NotNull(message = "通讯方式不能为空", groups = { EditGroup.class }) @NotNull(message = "通讯方式不能为空", groups = { EditGroup.class })
private Integer communicationMode; private Integer communicationMode;

View File

@ -21,13 +21,13 @@ public class DeviceTypeForm {
private Boolean isSupportBle; private Boolean isSupportBle;
@Schema(title = "定位方式", example = "0:无;1:GPS;2:基站;3:wifi;4:北斗") @Schema(title = "定位方式", example = "0:无;1:GPS;2:基站;3:wifi;4:北斗")
private String locateMode; private Integer locateMode;
@Schema(title = "联网方式", example = "0:无;1:4G;2:WIFI") @Schema(title = "联网方式", example = "0:无;1:4G;2:WIFI")
private String networkWay; private Integer networkWay;
@Schema(title = "通讯方式", example = "0:4G;1:蓝牙") @Schema(title = "通讯方式", example = "通讯方式 0:4G;1:蓝牙,2 4G&蓝牙")
private String communicationMode; private Integer communicationMode;
/** /**
* 型号字典用于APP页面跳转 * 型号字典用于APP页面跳转

View File

@ -59,7 +59,7 @@ public class APPDeviceQueryCriteria1 {
@Schema(name = "租户ID") @Schema(name = "租户ID")
private Long tenantId; private Long tenantId;
@Schema(name = "通讯方式", example = "0:4G;1:蓝牙") @Schema(name = "通讯方式", example = "通讯方式 0:4G;1:蓝牙,2 4G&蓝牙")
private Integer communicationMode; private Integer communicationMode;
} }

View File

@ -82,9 +82,10 @@ public class DeviceQueryCriteria extends BaseEntity {
private String tenantId; private String tenantId;
/** /**
* 通讯方式 0:4G;1:蓝牙 * 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
* communication_mode * communication_mode
*/ */
@Schema(title = "通讯方式", example = "0:4G;1:蓝牙,2 4G&蓝牙")
private Integer communicationMode; private Integer communicationMode;
/* app绑定用户id */ /* app绑定用户id */

View File

@ -26,7 +26,7 @@ public class AppDeviceVo implements Serializable {
private String deviceMac; private String deviceMac;
/** /**
* 通讯方式 0:4G;1:蓝牙 * 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
*/ */
private Integer communicationMode; private Integer communicationMode;

View File

@ -10,6 +10,7 @@ import com.fuyuanshen.common.excel.annotation.ExcelDictFormat;
import com.fuyuanshen.common.excel.convert.ExcelDictConvert; import com.fuyuanshen.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper; import io.github.linpeilie.annotations.AutoMapper;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data; import lombok.Data;
import java.io.Serial; import java.io.Serial;
@ -134,4 +135,5 @@ public class DeviceAlarmVo implements Serializable {
@Schema(name = "设备图片") @Schema(name = "设备图片")
private String devicePic; private String devicePic;
} }

View File

@ -27,7 +27,7 @@ public class WebDeviceVo implements Serializable {
private String deviceMac; private String deviceMac;
/** /**
* 通讯方式 0:4G;1:蓝牙 * 通讯方式 0:4G;1:蓝牙,2 4G&蓝牙
*/ */
private Integer communicationMode; private Integer communicationMode;

View File

@ -25,4 +25,13 @@ public interface DeviceAlarmMapper extends BaseMapperPlus<DeviceAlarm, DeviceAla
*/ */
Page<DeviceAlarmVo> selectVoPage( Page pageQuery,@Param("bo") DeviceAlarmBo bo); Page<DeviceAlarmVo> selectVoPage( Page pageQuery,@Param("bo") DeviceAlarmBo bo);
/**
* 根据设备IMEI查询最新的一条告警数据
*
* @param deviceImei 设备IMEI
* @return 设备告警
*/
DeviceAlarmVo selectLatestByDeviceImei(@Param("deviceImei") String deviceImei);
} }

View File

@ -109,4 +109,12 @@ public interface DeviceMapper extends BaseMapper<Device> {
int getUsageDataForMonth(@Param("deviceId") Long deviceId, int getUsageDataForMonth(@Param("deviceId") Long deviceId,
@Param("year") int year, @Param("year") int year,
@Param("month") int month); @Param("month") int month);
}
/**
* 根据设备IMEI查询设备
*
* @param deviceImei 设备IMEI
* @return 设备信息
*/
Device selectDeviceByImei(@Param("deviceImei") String deviceImei);
}

View File

@ -144,4 +144,12 @@ public interface DeviceService extends IService<Device> {
* @return * @return
*/ */
List<Map<String, Object>> getEquipmentUsageData(Long deviceTypeId, Integer range); List<Map<String, Object>> getEquipmentUsageData(Long deviceTypeId, Integer range);
}
/**
* 根据设备IMEI查询设备
*
* @param deviceImei 设备IMEI
* @return 设备信息
*/
Device selectDeviceByImei(String deviceImei);
}

View File

@ -65,4 +65,14 @@ public interface IDeviceAlarmService {
* @return 是否删除成功 * @return 是否删除成功
*/ */
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 根据设备IMEI查询最新的一条告警数据
*
* @param deviceImei 设备IMEI
* @return 设备告警
*/
DeviceAlarmVo queryLatestByDeviceImei(String deviceImei);
} }

View File

@ -1,5 +1,6 @@
package com.fuyuanshen.equipment.service.impl; package com.fuyuanshen.equipment.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.fuyuanshen.common.core.utils.MapstructUtils; import com.fuyuanshen.common.core.utils.MapstructUtils;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.mybatis.core.page.PageQuery; import com.fuyuanshen.common.mybatis.core.page.PageQuery;
@ -102,11 +103,13 @@ public class DeviceAlarmServiceImpl implements IDeviceAlarmService {
*/ */
@Override @Override
public Boolean insertByBo(DeviceAlarmBo bo) { public Boolean insertByBo(DeviceAlarmBo bo) {
DeviceAlarm add = MapstructUtils.convert(bo, DeviceAlarm.class); DeviceAlarm deviceAlarm = new DeviceAlarm();
validEntityBeforeSave(add); // DeviceAlarm add = MapstructUtils.convert(bo, DeviceAlarm.class);
boolean flag = baseMapper.insert(add) > 0; BeanUtil.copyProperties(bo, deviceAlarm);
validEntityBeforeSave(deviceAlarm);
boolean flag = baseMapper.insert(deviceAlarm) > 0;
if (flag) { if (flag) {
bo.setId(add.getId()); bo.setId(deviceAlarm.getId());
} }
return flag; return flag;
} }
@ -145,4 +148,17 @@ public class DeviceAlarmServiceImpl implements IDeviceAlarmService {
} }
return baseMapper.deleteByIds(ids) > 0; return baseMapper.deleteByIds(ids) > 0;
} }
/**
* 根据设备IMEI查询最新的一条告警数据
*
* @param deviceImei 设备IMEI
* @return 设备告警
*/
@Override
public DeviceAlarmVo queryLatestByDeviceImei(String deviceImei) {
return baseMapper.selectLatestByDeviceImei(deviceImei);
}
} }

View File

@ -58,6 +58,7 @@ public class DeviceFenceAccessRecordServiceImpl implements IDeviceFenceAccessRec
return TableDataInfo.build(result); return TableDataInfo.build(result);
} }
/** /**
* 查询符合条件的围栏进出记录列表 * 查询符合条件的围栏进出记录列表
* *
@ -70,6 +71,7 @@ public class DeviceFenceAccessRecordServiceImpl implements IDeviceFenceAccessRec
return baseMapper.selectVoPageWithFenceAndDeviceName(lqw); return baseMapper.selectVoPageWithFenceAndDeviceName(lqw);
} }
private LambdaQueryWrapper<DeviceFenceAccessRecord> buildQueryWrapper(DeviceFenceAccessRecordBo bo) { private LambdaQueryWrapper<DeviceFenceAccessRecord> buildQueryWrapper(DeviceFenceAccessRecordBo bo) {
Map<String, Object> params = bo.getParams(); Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<DeviceFenceAccessRecord> lqw = Wrappers.lambdaQuery(); LambdaQueryWrapper<DeviceFenceAccessRecord> lqw = Wrappers.lambdaQuery();
@ -86,6 +88,7 @@ public class DeviceFenceAccessRecordServiceImpl implements IDeviceFenceAccessRec
return lqw; return lqw;
} }
/** /**
* 新增围栏进出记录 * 新增围栏进出记录
* *

View File

@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fuyuanshen.equipment.domain.DeviceGeoFence; import com.fuyuanshen.equipment.domain.DeviceGeoFence;
import com.fuyuanshen.equipment.domain.bo.DeviceFenceAccessRecordBo;
import com.fuyuanshen.equipment.domain.bo.DeviceFenceStatusBo; import com.fuyuanshen.equipment.domain.bo.DeviceFenceStatusBo;
import com.fuyuanshen.equipment.domain.bo.DeviceGeoFenceBo; import com.fuyuanshen.equipment.domain.bo.DeviceGeoFenceBo;
import com.fuyuanshen.equipment.domain.dto.FenceCheckResponse; import com.fuyuanshen.equipment.domain.dto.FenceCheckResponse;
@ -16,6 +17,7 @@ import com.fuyuanshen.equipment.domain.query.FenceCheckRequest;
import com.fuyuanshen.equipment.domain.vo.DeviceFenceStatusVo; import com.fuyuanshen.equipment.domain.vo.DeviceFenceStatusVo;
import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo; import com.fuyuanshen.equipment.domain.vo.DeviceGeoFenceVo;
import com.fuyuanshen.equipment.mapper.DeviceGeoFenceMapper; import com.fuyuanshen.equipment.mapper.DeviceGeoFenceMapper;
import com.fuyuanshen.equipment.service.IDeviceFenceAccessRecordService;
import com.fuyuanshen.equipment.service.IDeviceFenceStatusService; import com.fuyuanshen.equipment.service.IDeviceFenceStatusService;
import com.fuyuanshen.equipment.service.IDeviceGeoFenceService; import com.fuyuanshen.equipment.service.IDeviceGeoFenceService;
import com.fuyuanshen.equipment.utils.map.GeoFenceChecker; import com.fuyuanshen.equipment.utils.map.GeoFenceChecker;
@ -40,6 +42,8 @@ public class DeviceGeoFenceServiceImpl implements IDeviceGeoFenceService {
private final DeviceGeoFenceMapper baseMapper; private final DeviceGeoFenceMapper baseMapper;
private final IDeviceFenceStatusService fenceStatusService; // 添加此行 private final IDeviceFenceStatusService fenceStatusService; // 添加此行
private final IDeviceFenceAccessRecordService fenceAccessRecordService; // 添加此行
@ -96,6 +100,7 @@ public class DeviceGeoFenceServiceImpl implements IDeviceGeoFenceService {
return lqw; return lqw;
} }
/** /**
* 新增电子围栏 * 新增电子围栏
* *
@ -213,9 +218,9 @@ public class DeviceGeoFenceServiceImpl implements IDeviceGeoFenceService {
DeviceFenceStatusVo latestStatus = fenceStatusService.getLatestStatusByDeviceAndFence( DeviceFenceStatusVo latestStatus = fenceStatusService.getLatestStatusByDeviceAndFence(
request.getDeviceId(), fence.getId()); request.getDeviceId(), fence.getId());
// 判断设备与围栏的关系变化 // 判断设备与围栏的关系变化 1=进入围栏,2=离开围栏
Long previousStatus = latestStatus != null ? latestStatus.getStatus() : 0L; // 默认在围栏外 Long previousStatus = latestStatus != null ? latestStatus.getStatus() : 2L; // 默认在围栏外
Long currentStatus = pointInFence ? 1L : 0L; // 当前状态1-在围栏内,0-在围栏外 Long currentStatus = pointInFence ? 1L : 2L; // 当前状态1-在围栏内,2-在围栏外
// 如果状态发生变化,则记录 // 如果状态发生变化,则记录
if (!previousStatus.equals(currentStatus)) { if (!previousStatus.equals(currentStatus)) {
@ -229,6 +234,17 @@ public class DeviceGeoFenceServiceImpl implements IDeviceGeoFenceService {
// 保存状态记录 // 保存状态记录
fenceStatusService.insertByBo(newStatus); fenceStatusService.insertByBo(newStatus);
// 添加围栏进出记录
DeviceFenceAccessRecordBo recordBo = new DeviceFenceAccessRecordBo();
recordBo.setDeviceId(request.getDeviceId());
recordBo.setFenceId(fence.getId());
recordBo.setLatitude(request.getLatitude());
recordBo.setLongitude(request.getLongitude());
recordBo.setEventTime(new Date());
// 1表示进入围栏2表示离开围栏
recordBo.setEventType(currentStatus);
fenceAccessRecordService.insertByBo(recordBo);
// 根据状态变化更新响应 // 根据状态变化更新响应
if (currentStatus == 1L) { if (currentStatus == 1L) {
// 设备进入围栏 // 设备进入围栏
@ -247,4 +263,4 @@ public class DeviceGeoFenceServiceImpl implements IDeviceGeoFenceService {
} }
} }

View File

@ -661,4 +661,9 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
} }
@Override
public Device selectDeviceByImei(String deviceImei) {
return baseMapper.selectDeviceByImei(deviceImei);
}
} }

View File

@ -6,7 +6,7 @@
<!-- 查询设备告警列表 --> <!-- 查询设备告警列表 -->
<select id="selectVoPage" resultType="com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo"> <select id="selectVoPage" resultType="com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo">
select *, d.device_mac as deviceMac, d.device_imei as deviceImei, select *, d.device_mac as deviceMac, d.device_imei as deviceImei,d.device_name as deviceName,
d.type_name as deviceTypeName, d.device_pic as devicePic d.type_name as deviceTypeName, d.device_pic as devicePic
from device_alarm da from device_alarm da
left join device d on da.device_id = d.id left join device d on da.device_id = d.id
@ -30,4 +30,20 @@
</where> </where>
</select> </select>
<!-- 根据设备IMEI查询最新的一条告警数据 -->
<select id="selectLatestByDeviceImei" resultType="com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo">
select *, d.device_mac as deviceMac, d.device_imei as deviceImei,
d.type_name as deviceTypeName, d.device_pic as devicePic
from device_alarm da
left join device d on da.device_id = d.id
left join device_type dt on dt.id = da.device_type
<where>
da.device_imei = #{deviceImei}
</where>
order by da.create_time desc
limit 1
</select>
</mapper> </mapper>

View File

@ -4,29 +4,26 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fuyuanshen.equipment.mapper.DeviceFenceAccessRecordMapper"> <mapper namespace="com.fuyuanshen.equipment.mapper.DeviceFenceAccessRecordMapper">
<!-- 分页查询围栏进出记录列表 --> <!-- 修改后的分页查询围栏进出记录列表 -->
<select id="selectVoPageWithFenceAndDeviceName" <select id="selectVoPageWithFenceAndDeviceName"
resultType="com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo"> resultType="com.fuyuanshen.equipment.domain.vo.DeviceFenceAccessRecordVo">
SELECT SELECT r.id,
r.id, r.fence_id,
r.fence_id, f.name AS fence_name,
f.name AS fence_name, r.device_id,
r.device_id, d.device_name,
d.device_name, r.user_id,
r.user_id, r.event_type,
r.event_type, r.latitude,
r.latitude, r.longitude,
r.longitude, r.accuracy,
r.accuracy, r.event_time,
r.event_time, r.create_time
r.create_time
FROM device_fence_access_record r FROM device_fence_access_record r
LEFT JOIN device_geo_fence f ON r.fence_id = f.id LEFT JOIN device_geo_fence f ON r.fence_id = f.id
LEFT JOIN device d ON r.device_id = d.id LEFT JOIN device d ON r.device_id = d.id
<where>
${ew.customSqlSegment} ${ew.customSqlSegment}
</where>
ORDER BY r.id ASC ORDER BY r.id ASC
</select> </select>
</mapper> </mapper>

View File

@ -423,4 +423,9 @@
AND MONTH (dl.create_time) = #{month} AND MONTH (dl.create_time) = #{month}
</select> </select>
<!-- 根据设备IMEI查询设备 -->
<select id="selectDeviceByImei" resultType="com.fuyuanshen.equipment.domain.Device">
SELECT * FROM device WHERE device_imei = #{deviceImei}
</select>
</mapper> </mapper>