diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java index 33c19f6..5e9a0ab 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/AppAuthController.java @@ -263,18 +263,21 @@ public class AppAuthController { @GetMapping("/version") public R> getAppVersion() { List list = dictTypeService.selectDictDataByType("app_version"); + list.forEach(d -> { - String[] arr = d.getRemark().split("\\|"); - d.setDictLabel(d.getDictLabel()); // ios/android - d.setDictValue(arr[0]); // 版本号 - d.setRemark(arr[1]); // 下载地址 + // 1. 安全拆分 + String[] arr = d.getRemark() == null ? new String[0] : d.getRemark().split("\\|"); + if (arr.length < 2) { // 格式不对 + log.warn("字典数据 app_version 格式非法:dictLabel={}, remark={}", d.getDictLabel(), d.getRemark()); + d.setDictValue(""); // 或者 d.setDictValue(d.getDictValue()); + d.setRemark(""); // 下载地址留空 + return; // 跳过 + } + // 2. 正常赋值 + d.setDictValue(arr[0].trim()); // 版本号 + d.setRemark(arr[1].trim()); // 下载地址 }); - // 只保留方法体:筛选 label=ios 且版本号 ≥ 2.5.0 的列表 -// List result = list.stream() -// .peek(d -> { String[] a = d.getRemark().split("\\|"); d.setDictValue(a[0]); d.setRemark(a[1]); }) -// .filter(d -> "ios".equalsIgnoreCase(d.getDictLabel())) -// .filter(d -> VersionComparator.INSTANCE.compare(d.getDictValue(), "2.5.0") >= 0) -// .toList(); + return R.ok(list); } diff --git a/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/AppDeviceXinghanController.java b/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/AppDeviceXinghanController.java index 15d9df5..3bb7028 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/AppDeviceXinghanController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/app/controller/device/AppDeviceXinghanController.java @@ -10,6 +10,7 @@ import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation; import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessBatcAnnotation; import com.fuyuanshen.common.web.core.BaseController; import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo; +import com.fuyuanshen.web.domain.Dto.DeviceXinghanInstructDto; import com.fuyuanshen.web.service.device.DeviceBJQBizService; import com.fuyuanshen.web.service.device.DeviceXinghanBizService; import lombok.RequiredArgsConstructor; @@ -70,7 +71,7 @@ public class AppDeviceXinghanController extends BaseController { */ @Log(title = "xinghan指令-静电预警档位") @PostMapping("/DetectGradeSettings") - public R DetectGradeSettings(@RequestBody DeviceInstructDto params) { + public R DetectGradeSettings(@RequestBody DeviceXinghanInstructDto params) { // params 转 JSONObject appDeviceService.upDetectGradeSettings(params); return R.ok(); @@ -82,7 +83,7 @@ public class AppDeviceXinghanController extends BaseController { */ @Log(title = "xinghan指令-照明档位") @PostMapping("/LightGradeSettings") - public R LightGradeSettings(@RequestBody DeviceInstructDto params) { + public R LightGradeSettings(@RequestBody DeviceXinghanInstructDto params) { // params 转 JSONObject appDeviceService.upLightGradeSettings(params); return R.ok(); @@ -94,7 +95,7 @@ public class AppDeviceXinghanController extends BaseController { */ @Log(title = "xinghan指令-SOS档位s") @PostMapping("/SOSGradeSettings") - public R SOSGradeSettings(@RequestBody DeviceInstructDto params) { + public R SOSGradeSettings(@RequestBody DeviceXinghanInstructDto params) { // params 转 JSONObject appDeviceService.upSOSGradeSettings(params); return R.ok(); @@ -106,7 +107,7 @@ public class AppDeviceXinghanController extends BaseController { */ @Log(title = "xinghan指令-静止报警状态") @PostMapping("/ShakeBitSettings") - public R ShakeBitSettings(@RequestBody DeviceInstructDto params) { + public R ShakeBitSettings(@RequestBody DeviceXinghanInstructDto params) { // params 转 JSONObject appDeviceService.upShakeBitSettings(params); return R.ok(); diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/base/MqttXinghanJson.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/base/MqttXinghanJson.java index 3e0737f..a487d0d 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/base/MqttXinghanJson.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/base/MqttXinghanJson.java @@ -61,5 +61,14 @@ public class MqttXinghanJson { */ @JsonProperty("sta_latitude") public String stalatitude; + /** + * 第十二键值对,系统现状,0关机,1仅充电,2开机未充电,3,开机且充电 + */ + @JsonProperty("sta_system") + public String stasystem; + /** + * 电量百分比(适配控制列表显示) + */ + public String batteryPercentage; } diff --git a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/xinghan/XinghanDeviceDataRule.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/xinghan/XinghanDeviceDataRule.java index cf4fbd0..cbcf2ea 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/xinghan/XinghanDeviceDataRule.java +++ b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/xinghan/XinghanDeviceDataRule.java @@ -1,33 +1,42 @@ package com.fuyuanshen.global.mqtt.rule.xinghan; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson2.JSONObject; import com.fasterxml.jackson.databind.ObjectMapper; import com.fuyuanshen.common.core.constant.GlobalConstants; import com.fuyuanshen.common.core.utils.StringUtils; +import com.fuyuanshen.common.core.utils.date.DurationUtils; import com.fuyuanshen.common.json.utils.JsonUtils; import com.fuyuanshen.common.redis.utils.RedisUtils; +import com.fuyuanshen.equipment.domain.Device; +import com.fuyuanshen.equipment.domain.bo.DeviceAlarmBo; +import com.fuyuanshen.equipment.domain.vo.DeviceAlarmVo; +import com.fuyuanshen.equipment.mapper.DeviceAlarmMapper; +import com.fuyuanshen.equipment.service.DeviceService; +import com.fuyuanshen.equipment.service.IDeviceAlarmService; import com.fuyuanshen.equipment.utils.map.GetAddressFromLatUtil; import com.fuyuanshen.equipment.utils.map.LngLonUtil; import com.fuyuanshen.global.mqtt.base.MqttMessageRule; import com.fuyuanshen.global.mqtt.base.MqttRuleContext; import com.fuyuanshen.global.mqtt.base.MqttXinghanJson; import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; -import com.fuyuanshen.global.mqtt.constants.LightingCommandTypeConstants; import com.fuyuanshen.global.mqtt.constants.XingHanCommandTypeConstants; import com.fuyuanshen.global.mqtt.listener.domain.FunctionAccessStatus; +import com.fuyuanshen.web.enums.AlarmTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.beans.factory.annotation.Autowired; import java.time.Duration; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.CompletableFuture; 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.DEVICE_KEY_PREFIX; @@ -57,6 +66,9 @@ public class XinghanDeviceDataRule implements MqttMessageRule { @Autowired private ObjectMapper objectMapper; + private final IDeviceAlarmService deviceAlarmService; + private final DeviceService deviceService; + private final DeviceAlarmMapper deviceAlarmMapper; @Override public void execute(MqttRuleContext context) { @@ -65,7 +77,7 @@ public class XinghanDeviceDataRule implements MqttMessageRule { // Latitude, longitude //主灯档位,激光灯档位,电量百分比,充电状态,电池剩余续航时间 MqttXinghanJson deviceStatus = objectMapper.convertValue(context.getPayloadDict(), MqttXinghanJson.class); - + deviceStatus.setBatteryPercentage(deviceStatus.getStaPowerPercent().toString()); // 发送设备状态和位置信息到Redis asyncSendDeviceDataToRedisWithFuture(context.getDeviceImei(),deviceStatus); RedisUtils.setCacheObject(functionAccess, FunctionAccessStatus.OK.getCode(), Duration.ofSeconds(20)); @@ -99,12 +111,113 @@ public class XinghanDeviceDataRule implements MqttMessageRule { // 异步发送经纬度到Redis asyncSendLocationToRedisWithFuture(deviceImei, deviceStatus.getStalatitude(), deviceStatus.getStalongitude()); + // 保存报警信息 + saveAlarm(deviceImei,deviceStatus); + } catch (Exception e) { log.error("异步发送设备信息到Redis时出错: device={}, error={}", deviceImei, e.getMessage(), e); } }); } + /** + * 入口:保存报警(SOS 与 Shake 完全独立) + */ + public void saveAlarm(String deviceImei, MqttXinghanJson status) { + int sos = Optional.ofNullable(status.getStaSOSGrade()).orElse(0); + // 1. 处理 SOS 报警 + handleSingleAlarm(deviceImei, + sos > 0, + AlarmTypeEnum.SOS); + int shake = Optional.ofNullable(status.getStaShakeBit()).orElse(0); + // 2. 处理 Shake 报警 + handleSingleAlarm(deviceImei, + shake > 0, + AlarmTypeEnum.SHAKE); + } + + /** + * 通用:对单个报警源的“开始/结束”生命周期管理 + */ + private void handleSingleAlarm(String deviceImei, boolean nowAlarming, AlarmTypeEnum type) { + String redisKey = buildAlarmRedisKey(deviceImei, type); + + Long alarmId = RedisUtils.getCacheObject(redisKey); + + // ---------- 情况 1:当前正在报警 ---------- + if (nowAlarming) { + // 已存在未结束报警 -> 什么都不做(同一条报警) + if (alarmId != null) { + // key 还在 -> 同一条报警,只续期 + RedisUtils.setCacheObject(redisKey, alarmId, Duration.ofMinutes(10)); + return; + } + // 不存在 -> 新建 + DeviceAlarmBo bo = createAlarmBo(deviceImei, type); + deviceAlarmService.insertByBo(bo); + RedisUtils.setCacheObject(redisKey, bo.getId(), Duration.ofMinutes(10)); // 5分钟后结束过期 + return; + } + + // ---------- 情况 2:当前不报警 ---------- + if (alarmId != null) { + // 结束它 + finishAlarm(alarmId); + RedisUtils.deleteObject(redisKey); + } + } + + /** + * 结束报警:写库 + */ + private void finishAlarm(Long alarmId) { + DeviceAlarmVo vo = deviceAlarmService.queryById(alarmId); + if (vo == null || vo.getTreatmentState() == 0) { + return; // 已处理或已被删 + } + DeviceAlarmBo bo = BeanUtil.toBean(vo, DeviceAlarmBo.class); + bo.setFinishTime(new Date()); + bo.setDurationTime(DurationUtils.getDurationBetween(vo.getStartTime(), bo.getFinishTime())); + bo.setTreatmentState(0); // 已处理 + deviceAlarmService.updateByBo(bo); + } + + /** + * 新建报警 Bo + */ + private DeviceAlarmBo createAlarmBo(String deviceImei, AlarmTypeEnum type) { + Device device = deviceService.selectDeviceByImei(deviceImei); + if (device == null) { + return null; + } + DeviceAlarmBo bo = new DeviceAlarmBo(); + bo.setDeviceId(device.getId()); + bo.setDeviceImei(deviceImei); + bo.setDeviceAction(2); // 自动报警 + bo.setStartTime(new Date()); + bo.setTreatmentState(1); // 未处理 + bo.setTenantId(device.getTenantId()); + + // 报警内容 + bo.setContent("自动报警:" + type.getDesc()); + + // 位置 + String location = RedisUtils.getCacheObject( + GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX); + if (StrUtil.isNotBlank(location)) { + bo.setLocation(JSONObject.parseObject(location).getString("address")); + } + return bo; + } + + /** + * key 构建 + */ + private String buildAlarmRedisKey(String deviceImei, AlarmTypeEnum type) { + return StrUtil.format("{}{}{}{}:alarm_id", + GLOBAL_REDIS_KEY, DEVICE_KEY_PREFIX, deviceImei, type.getSuffix()); + } + /** * 异步发送位置信息到Redis(使用CompletableFuture) * diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceXinghanController.java b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceXinghanController.java index 4cc51d8..2f1c324 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceXinghanController.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/controller/device/DeviceXinghanController.java @@ -10,6 +10,7 @@ import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessAnnotation; import com.fuyuanshen.common.ratelimiter.annotation.FunctionAccessBatcAnnotation; import com.fuyuanshen.common.web.core.BaseController; import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo; +import com.fuyuanshen.web.domain.Dto.DeviceXinghanInstructDto; import com.fuyuanshen.web.domain.vo.DeviceXinghanDetailVo; import com.fuyuanshen.web.service.device.DeviceXinghanBizService; import jakarta.validation.constraints.NotNull; @@ -80,7 +81,7 @@ public class DeviceXinghanController extends BaseController { * 3,2,1,0,分别表示高档/中档/低挡/关闭 */ @PostMapping("/DetectGradeSettings") - public R DetectGradeSettings(@RequestBody DeviceInstructDto params) { + public R DetectGradeSettings(@RequestBody DeviceXinghanInstructDto params) { // params 转 JSONObject deviceXinghanBizService.upDetectGradeSettings(params); return R.ok(); @@ -91,7 +92,7 @@ public class DeviceXinghanController extends BaseController { * 照明档位,2,1,0,分别表示弱光/强光/关闭 */ @PostMapping("/LightGradeSettings") - public R LightGradeSettings(@RequestBody DeviceInstructDto params) { + public R LightGradeSettings(@RequestBody DeviceXinghanInstructDto params) { // params 转 JSONObject deviceXinghanBizService.upLightGradeSettings(params); return R.ok(); @@ -102,7 +103,7 @@ public class DeviceXinghanController extends BaseController { * SOS档位,2,1,0, 分别表示红蓝模式/爆闪模式/关闭 */ @PostMapping("/SOSGradeSettings") - public R SOSGradeSettings(@RequestBody DeviceInstructDto params) { + public R SOSGradeSettings(@RequestBody DeviceXinghanInstructDto params) { // params 转 JSONObject deviceXinghanBizService.upSOSGradeSettings(params); return R.ok(); @@ -113,7 +114,7 @@ public class DeviceXinghanController extends BaseController { * 静止报警状态,0-未静止报警,1-正在静止报警。 */ @PostMapping("/ShakeBitSettings") - public R ShakeBitSettings(@RequestBody DeviceInstructDto params) { + public R ShakeBitSettings(@RequestBody DeviceXinghanInstructDto params) { // params 转 JSONObject deviceXinghanBizService.upShakeBitSettings(params); return R.ok(); diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/domain/Dto/DeviceXinghanInstructDto.java b/fys-admin/src/main/java/com/fuyuanshen/web/domain/Dto/DeviceXinghanInstructDto.java new file mode 100644 index 0000000..0d3b598 --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/domain/Dto/DeviceXinghanInstructDto.java @@ -0,0 +1,15 @@ +package com.fuyuanshen.web.domain.Dto; + +import lombok.Data; + +@Data +public class DeviceXinghanInstructDto { + private Long deviceId; + + private String deviceImei; + /** + * 下发指令 + */ + private String instructValue; + private Boolean isBluetooth = false; +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/enums/AlarmTypeEnum.java b/fys-admin/src/main/java/com/fuyuanshen/web/enums/AlarmTypeEnum.java new file mode 100644 index 0000000..bde6fdc --- /dev/null +++ b/fys-admin/src/main/java/com/fuyuanshen/web/enums/AlarmTypeEnum.java @@ -0,0 +1,17 @@ +package com.fuyuanshen.web.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 报警类型枚举 + */ +@AllArgsConstructor +@Getter +public enum AlarmTypeEnum { + SOS("_sos", "SOS报警"), + SHAKE("_shake", "静止报警"); + + private final String suffix; + private final String desc; +} diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceDebugService.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceDebugService.java index 2f2e6b8..d4b875a 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceDebugService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceDebugService.java @@ -10,18 +10,15 @@ import com.fuyuanshen.app.service.IAppBusinessFileService; import com.fuyuanshen.app.service.IAppOperationVideoService; import com.fuyuanshen.common.core.exception.ServiceException; import com.fuyuanshen.common.satoken.utils.AppLoginHelper; -import com.fuyuanshen.equipment.mapper.DeviceMapper; import com.fuyuanshen.equipment.service.DeviceService; import com.fuyuanshen.system.domain.vo.SysOssVo; import com.fuyuanshen.system.service.ISysOssService; import com.fuyuanshen.web.domain.vo.DeviceInfoVo; -import com.fuyuanshen.web.util.FileHashUtil; -import io.swagger.v3.oas.annotations.Operation; +import com.fuyuanshen.equipment.utils.FileHashUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; diff --git a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceXinghanBizService.java b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceXinghanBizService.java index 3225459..617458c 100644 --- a/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceXinghanBizService.java +++ b/fys-admin/src/main/java/com/fuyuanshen/web/service/device/DeviceXinghanBizService.java @@ -1,6 +1,7 @@ package com.fuyuanshen.web.service.device; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -28,17 +29,21 @@ import com.fuyuanshen.common.redis.utils.RedisUtils; import com.fuyuanshen.common.satoken.utils.AppLoginHelper; import com.fuyuanshen.equipment.domain.Device; import com.fuyuanshen.equipment.domain.DeviceType; +import com.fuyuanshen.equipment.domain.bo.DeviceAlarmBo; import com.fuyuanshen.equipment.domain.dto.AppDeviceSendMsgBo; import com.fuyuanshen.equipment.enums.LightModeEnum; import com.fuyuanshen.equipment.mapper.DeviceLogMapper; import com.fuyuanshen.equipment.mapper.DeviceMapper; import com.fuyuanshen.equipment.mapper.DeviceTypeMapper; +import com.fuyuanshen.equipment.service.IDeviceAlarmService; import com.fuyuanshen.global.mqtt.base.MqttXinghanJson; import com.fuyuanshen.global.mqtt.config.MqttGateway; import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; import com.fuyuanshen.global.mqtt.constants.MqttConstants; import com.fuyuanshen.web.domain.Dto.DeviceDebugLogoUploadDto; +import com.fuyuanshen.web.domain.Dto.DeviceXinghanInstructDto; import com.fuyuanshen.web.domain.vo.DeviceXinghanDetailVo; +import com.fuyuanshen.web.enums.AlarmTypeEnum; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -68,6 +73,7 @@ public class DeviceXinghanBizService { private final MqttGateway mqttGateway; private final DeviceLogMapper deviceLogMapper; private final AppPersonnelInfoRecordsMapper appPersonnelInfoRecordsMapper; + private final IDeviceAlarmService deviceAlarmService; @Autowired private ObjectMapper objectMapper; @@ -95,28 +101,39 @@ public class DeviceXinghanBizService { /** * 设置静电预警档位 */ - public void upDetectGradeSettings(DeviceInstructDto dto) { + public void upDetectGradeSettings(DeviceXinghanInstructDto dto) { sendCommand(dto, "ins_DetectGrade","静电预警档位"); } /** * 设置照明档位 */ - public void upLightGradeSettings(DeviceInstructDto dto) { + public void upLightGradeSettings(DeviceXinghanInstructDto dto) { sendCommand(dto, "ins_LightGrade","照明档位"); } /** * 设置SOS档位 */ - public void upSOSGradeSettings(DeviceInstructDto dto) { - sendCommand(dto, "ins_SOSGrade","SOS档位"); + public void upSOSGradeSettings(DeviceXinghanInstructDto dto) { + if(dto.getIsBluetooth()){ + long deviceId = dto.getDeviceId(); + + // 1. 使用Optional简化空值检查,使代码更简洁 + Device device = Optional.ofNullable(deviceMapper.selectById(deviceId)) + .orElseThrow(() -> new ServiceException("设备不存在")); + int sosGrade = Integer.parseInt(dto.getInstructValue()); + // 6. 新建报警信息 + createAlarm(device.getId(),device.getDeviceImei(),"ins_SOSGrade",sosGrade); + }else { + sendCommand(dto, "ins_SOSGrade","SOS档位"); + } } /** * 设置强制报警 */ - public void upShakeBitSettings(DeviceInstructDto dto) { + public void upShakeBitSettings(DeviceXinghanInstructDto dto) { sendCommand(dto, "ins_ShakeBit","强制报警"); } @@ -465,7 +482,7 @@ public class DeviceXinghanBizService { * @param payloadKey 指令负载数据的键名 * @param deviceAction 设备操作类型描述 */ - private void sendCommand(DeviceInstructDto dto, String payloadKey, String deviceAction) { + private void sendCommand(DeviceXinghanInstructDto dto, String payloadKey, String deviceAction) { long deviceId = dto.getDeviceId(); // 1. 使用Optional简化空值检查,使代码更简洁 @@ -509,6 +526,9 @@ public class DeviceXinghanBizService { deviceAction, content, AppLoginHelper.getUserId()); + + // 6. 新建报警信息 + createAlarm(device.getId(),deviceImei,payloadKey,value); } // private boolean isDeviceOffline(String imei) { @@ -516,6 +536,48 @@ public class DeviceXinghanBizService { // return getDeviceStatus(imei); // } + /** + * 新建报警 Bo + */ + private void createAlarm(Long deviceId, String deviceImei, + String payloadKey, int value) { + // 这里直接放你原来的 createAlarmBo 全部逻辑 + if (!"ins_SOSGrade".equals(payloadKey) || value == 0) { + return; + } + AlarmTypeEnum type = value == 1 ? AlarmTypeEnum.SOS : AlarmTypeEnum.SHAKE; + String redisKey = buildAlarmRedisKey(deviceImei, type); + Long alarmId = RedisUtils.getCacheObject(redisKey); + // 已存在未结束报警 -> 什么都不做(同一条报警) + if (alarmId != null) { + // key 还在 -> 同一条报警,只续期 + RedisUtils.setCacheObject(redisKey, alarmId, Duration.ofMinutes(10)); + return; + } + // 不存在 -> 新建 + DeviceAlarmBo bo = new DeviceAlarmBo(); + bo.setDeviceId(deviceId); + bo.setDeviceImei(deviceImei); + bo.setDeviceAction(0); // 强制报警 + bo.setStartTime(new Date()); + bo.setTreatmentState(1); // 未处理 + bo.setContent("强制报警:" + type.getDesc()); + String location = RedisUtils.getCacheObject(GLOBAL_REDIS_KEY + DEVICE_KEY_PREFIX + deviceImei + DEVICE_LOCATION_KEY_PREFIX); + if (StrUtil.isNotBlank(location)) { + bo.setLocation(JSONObject.parseObject(location).getString("address")); + } + deviceAlarmService.insertByBo(bo); + RedisUtils.setCacheObject(redisKey, bo.getId(), Duration.ofMinutes(10)); + } + + /** + * key 构建 + */ + private String buildAlarmRedisKey(String deviceImei, AlarmTypeEnum type) { + return StrUtil.format("{}{}{}{}:alarm_id", + GLOBAL_REDIS_KEY, DEVICE_KEY_PREFIX, deviceImei, type.getSuffix()); + } + /** * 记录设备操作日志 * @param deviceId 设备ID diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceRepairRecordsBo.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceRepairRecordsBo.java index e134543..e463172 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceRepairRecordsBo.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/bo/DeviceRepairRecordsBo.java @@ -11,6 +11,8 @@ import lombok.Data; import lombok.EqualsAndHashCode; import jakarta.validation.constraints.*; import java.util.Date; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonFormat; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.multipart.MultipartFile; @@ -70,4 +72,6 @@ public class DeviceRepairRecordsBo extends BaseEntity { @Schema(title = "维修后图片") @JsonIgnore private MultipartFile afterFile; + + private List imageIds; } diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/query/DeviceRepairRecordsQueryCriteria.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/query/DeviceRepairRecordsQueryCriteria.java index 4df5ec6..bf9ba0f 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/query/DeviceRepairRecordsQueryCriteria.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/query/DeviceRepairRecordsQueryCriteria.java @@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.multipart.MultipartFile; import java.util.Date; @@ -51,8 +52,10 @@ public class DeviceRepairRecordsQueryCriteria extends BaseEntity { private String repairPerson; @Schema(title = "维修开始时间") + @DateTimeFormat(pattern = "yyyy-MM-dd") private Date repairBeginTime; @Schema(title = "维修结束时间") + @DateTimeFormat(pattern = "yyyy-MM-dd") private Date repairEndTime; @Schema(title = "所属客户") diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceRepairRecordsServiceImpl.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceRepairRecordsServiceImpl.java index 3b838d8..80ff0fe 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceRepairRecordsServiceImpl.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceRepairRecordsServiceImpl.java @@ -18,6 +18,7 @@ import com.fuyuanshen.equipment.domain.vo.DeviceRepairImagesVo; import com.fuyuanshen.equipment.enums.RepairImageType; import com.fuyuanshen.equipment.mapper.DeviceMapper; import com.fuyuanshen.equipment.mapper.DeviceRepairImagesMapper; +import com.fuyuanshen.equipment.utils.FileHashUtil; import com.fuyuanshen.system.domain.vo.SysOssVo; import com.fuyuanshen.system.service.ISysOssService; import lombok.RequiredArgsConstructor; @@ -32,6 +33,7 @@ import com.fuyuanshen.equipment.service.IDeviceRepairRecordsService; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; import java.util.*; /** @@ -178,6 +180,10 @@ public class DeviceRepairRecordsServiceImpl extends ServiceImpl images = new ArrayList<>(2); @@ -200,12 +206,28 @@ public class DeviceRepairRecordsServiceImpl extends ServiceImpl + + and d.device_name like concat('%', TRIM(#{criteria.searchValue}), '%') + and dr.device_id = #{criteria.deviceId}