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/rule/xinghan/XinghanDeviceDataRule.java b/fys-admin/src/main/java/com/fuyuanshen/global/mqtt/rule/xinghan/XinghanDeviceDataRule.java index 6fc2f5f..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 @@ -23,6 +23,7 @@ import com.fuyuanshen.global.mqtt.base.MqttXinghanJson; import com.fuyuanshen.global.mqtt.constants.DeviceRedisKeyConstants; 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; @@ -127,18 +128,18 @@ public class XinghanDeviceDataRule implements MqttMessageRule { // 1. 处理 SOS 报警 handleSingleAlarm(deviceImei, sos > 0, - AlarmType.SOS); + AlarmTypeEnum.SOS); int shake = Optional.ofNullable(status.getStaShakeBit()).orElse(0); // 2. 处理 Shake 报警 handleSingleAlarm(deviceImei, shake > 0, - AlarmType.SHAKE); + AlarmTypeEnum.SHAKE); } /** * 通用:对单个报警源的“开始/结束”生命周期管理 */ - private void handleSingleAlarm(String deviceImei, boolean nowAlarming, AlarmType type) { + private void handleSingleAlarm(String deviceImei, boolean nowAlarming, AlarmTypeEnum type) { String redisKey = buildAlarmRedisKey(deviceImei, type); Long alarmId = RedisUtils.getCacheObject(redisKey); @@ -184,7 +185,7 @@ public class XinghanDeviceDataRule implements MqttMessageRule { /** * 新建报警 Bo */ - private DeviceAlarmBo createAlarmBo(String deviceImei, AlarmType type) { + private DeviceAlarmBo createAlarmBo(String deviceImei, AlarmTypeEnum type) { Device device = deviceService.selectDeviceByImei(deviceImei); if (device == null) { return null; @@ -212,24 +213,11 @@ public class XinghanDeviceDataRule implements MqttMessageRule { /** * key 构建 */ - private String buildAlarmRedisKey(String deviceImei, AlarmType type) { + private String buildAlarmRedisKey(String deviceImei, AlarmTypeEnum type) { return StrUtil.format("{}{}{}{}:alarm_id", GLOBAL_REDIS_KEY, DEVICE_KEY_PREFIX, deviceImei, type.getSuffix()); } - /** - * 报警类型枚举 - */ - @AllArgsConstructor - @Getter - enum AlarmType { - SOS("_sos", "SOS报警"), - SHAKE("_shake", "静止报警"); - - private final String suffix; - private final String desc; - } - /** * 异步发送位置信息到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/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