ソースを参照

修复车辆抓拍无图片问题

zhaojinyu 2 日 前
コミット
ec1bf8b736

+ 368 - 123
service-sas/service-sas-biz/src/main/java/com/usky/sas/mqtt/MqttService.java

@@ -562,118 +562,40 @@ public class MqttService {
 
             if ("event".equals(method)) {
                 ParkingEventResult eventResult = this.mapper.readValue(payload, ParkingEventResult.class);
-
+                
+                // 【HTTP增强】尝试通过HTTP获取详细信息
                 SasConfig config = sasConfigService.getConfig();
-                if (config == null || StrUtil.isBlank(config.getHost()) || StrUtil.isBlank(config.getKeyds())) {
-                    log.error("停车场事件处理失败:系统配置未初始化或host/keyds为空");
-                    return;
-                }
-
-                Map<String, Object> map = new HashMap<>();
-                map.put("eventId", eventResult.getId());
-                JsonRpcRequest getParkingEventInfoJson = new JsonRpcRequest("getEvent", map, (Long)null);
-                Map<String, Object> getParkingEventInfo = new HashMap<>();
-                getParkingEventInfo.put("key", config.getKeyds());
-                getParkingEventInfo.put("json", getParkingEventInfoJson.toString());
-                log.info("请求AG报文:{}", JSONUtil.toJsonStr(getParkingEventInfo));
-
-                String resultEvent = HttpUtil.post(config.getHost() + "/agbox/device/parking", getParkingEventInfo);
-                log.info("请求AG响应:{}", resultEvent);
-
-                if (StrUtil.isBlank(resultEvent)) {
-                    log.error("停车场事件:AG接口返回空字符串,终止处理");
-                    return;
-                }
-
-                ParkingEventInfoVo parkingEventInfoVo = this.mapper.readValue(resultEvent, ParkingEventInfoVo.class);
-                if (parkingEventInfoVo == null) {
-                    log.error("停车场事件:解析返回结果为null,响应:{}", resultEvent);
-                    return;
-                }
-
-                ParkingEventInfoResult result = parkingEventInfoVo.getResult();
-                if (result == null) {
-                    log.error("停车场事件:返回结果result为null,响应:{}", resultEvent);
-                    return;
-                }
-
-                ParkingEventInfo eventInfo = result.getEventInfo();
-                if (eventInfo == null) {
-                    log.error("停车场事件:eventInfo为null,响应:{}", resultEvent);
-                    return;
-                }
-
-                SasParkingEvent bean = BeanUtil.toBean(eventInfo, SasParkingEvent.class);
-                bean.setCreateTime(LocalDateTime.parse(eventInfo.getReceivingTime(), this.formatter));
-                bean.setTriggerTime(LocalDateTime.parse(eventInfo.getTriggerTime(), this.formatter));
-                bean.setEventId(eventResult.getId());
-                bean.setAccessType(eventInfo.getIo());
-                bean.setCarType(eventInfo.getCarCode());
-                bean.setPlateType(eventInfo.getPlateCode());
-
-                if (eventInfo.getEventPic() != null) {
-                    SasPic pic = BeanUtil.toBean(eventInfo.getEventPic(), SasPic.class);
-                    pic.setId(IdUtil.randomUUID());
-                    this.sasPicMapper.insert(pic);
-                    bean.setEventPicId(pic.getId());
-                }
-
-                if (eventInfo.getPlacePic() != null) {
-                    SasPic pic = BeanUtil.toBean(eventInfo.getPlacePic(), SasPic.class);
-                    pic.setId(IdUtil.randomUUID());
-                    this.sasPicMapper.insert(pic);
-                    bean.setPlatePicId(pic.getId());
-                }
-
-                if (eventInfo.getEventCode() == null && root.get("code") != null) {
-                    eventInfo.setEventCode(root.get("code").asInt());
-                }
-
-                SasDevice device = findDevice(eventInfo.getDeviceId(), SystemTypeCodeEnum.parking.getCode());
-                if (device == null) {
-                    log.warn("设备不存在,丢弃停车场事件: deviceId={}", eventInfo.getDeviceId());
-                    return;
-                }
-
-                SasParkingEvent event = new SasParkingEvent();
-                String eventId = StrUtil.isNotBlank(eventResult.getId()) ? eventResult.getId() : IdUtil.randomUUID();
-                if (parkingEventService.getById(eventId) != null) {
-                    log.info("停车场事件已存在, 跳过保存, eventId={}", eventId);
-                    return;
-                }
-                event.setEventId(eventId);
-                BeanUtil.copyProperties(eventInfo, event, "eventId");
-                event.setTriggerTime(parseTime(eventInfo.getTriggerTime()));
-                event.setCreateTime(LocalDateTime.now());
-                event.setUpdateTime(LocalDateTime.now());
-
-                parkingEventService.save(event);
-
-                BrieflyEventInfo info = BeanUtil.toBean(event, BrieflyEventInfo.class);
-                info.setTriggerTime(eventInfo.getTriggerTime());
-                info.setCreateTime(LocalDateTime.now().format(formatter));
-
-                if (eventInfo.getEventPic() != null) {
-                    info.setEventUrl(eventInfo.getEventPic().getUrl() + eventInfo.getEventPic().getPath());
-                }
-                if (eventInfo.getPlacePic() != null) {
-                    info.setEventUrl(eventInfo.getPlacePic().getUrl() + eventInfo.getPlacePic().getPath());
-                }
-
-                SasParkingEventCode code = parkingEventCodeMapper.selectById(event.getEventCode());
-                if (code != null) {
-                    info.setEventTypeName(code.getName());
-                }
-
-                enrichDeviceInfo(info, device);
-                SasEventTypeGroup eventTypeGroup = findEventTypeGroup(SystemTypeCodeEnum.parking.getCode());
-                if (eventTypeGroup != null) {
-                    info.setEventLevelId(eventTypeGroup.getEventLevel());
+                if (config != null && StrUtil.isNotBlank(config.getHost()) && StrUtil.isNotBlank(config.getKeyds())) {
+                    try {
+                        Map<String, Object> map = new HashMap<>();
+                        map.put("eventId", eventResult.getId());
+                        JsonRpcRequest getParkingEventInfoJson = new JsonRpcRequest("getEvent", map, (Long)null);
+                        Map<String, Object> getParkingEventInfo = new HashMap<>();
+                        getParkingEventInfo.put("key", config.getKeyds());
+                        getParkingEventInfo.put("json", getParkingEventInfoJson.toString());
+                        log.info("【停车场】请求AG详细信息报文:{}", JSONUtil.toJsonStr(getParkingEventInfo));
+
+                        String resultEvent = HttpUtil.post(config.getHost() + "/agbox/device/parking", getParkingEventInfo);
+                        log.info("【停车场】请求AG响应:{}", resultEvent);
+
+                        if (StrUtil.isNotBlank(resultEvent)) {
+                            ParkingEventInfoVo parkingEventInfoVo = this.mapper.readValue(resultEvent, ParkingEventInfoVo.class);
+                            if (parkingEventInfoVo != null && parkingEventInfoVo.getResult() != null && parkingEventInfoVo.getResult().getEventInfo() != null) {
+                                // HTTP获取成功,使用详细信息处理
+                                ParkingEventInfo eventInfo = parkingEventInfoVo.getResult().getEventInfo();
+                                processParkingEventWithHttpInfo(eventInfo, eventResult);
+                                return;
+                            }
+                        }
+                    } catch (Exception httpEx) {
+                        log.warn("【停车场】HTTP获取详细信息失败,降级到MQTT处理:{}", httpEx.getMessage());
+                        // 降级到MQTT处理
+                    }
                 }
-                info.setDeviceType(SystemTypeCodeEnum.parking.getCode());
-                SasWebSocket.sendAll(info);
-
-                log.info("停车场事件保存并推送成功, eventId={}", event.getEventId());
+                
+                // MQTT基础处理(降级方案)
+                log.info("【停车场】使用MQTT基础信息处理");
+                processParkingEventWithMqttInfo(eventResult, root);
             } else if ("heart".equals(method)) {
                 handleHeartbeat(payload, SystemTypeCodeEnum.parking.getCode());
             }
@@ -771,19 +693,51 @@ public class MqttService {
 
             // 【核心修复】匹配真实设备的 method: "event"
             if ("event".equals(method)) {
-                // 直接从根节点读取所有字段,完全适配你真实的消息格式
+                // 从MQTT获取基础信息
+                String id = root.path("id").asText();
                 String deviceId = root.path("deviceId").asText();
+                
+                // 打印日志,确认字段都读到了
+                log.info("【入侵告警】收到MQTT消息:deviceId={}, id={}", deviceId, id);
+
+                // 【HTTP增强】尝试通过HTTP获取详细信息
+                SasConfig config = sasConfigService.getConfig();
+                if (config != null && StrUtil.isNotBlank(config.getHost()) && StrUtil.isNotBlank(config.getKeyds())) {
+                    try {
+                        Map<String, Object> map = new HashMap<>();
+                        map.put("eventId", id);
+                        JsonRpcRequest getAlarmEventInfoJson = new JsonRpcRequest("getEvent", map, (Long)null);
+                        Map<String, Object> getAlarmEventInfo = new HashMap<>();
+                        getAlarmEventInfo.put("key", config.getKeyds());
+                        getAlarmEventInfo.put("json", getAlarmEventInfoJson.toString());
+                        log.info("【入侵告警】请求AG详细信息报文:{}", JSONUtil.toJsonStr(getAlarmEventInfo));
+
+                        String resultEvent = HttpUtil.post(config.getHost() + "/agbox/device/alarm", getAlarmEventInfo);
+                        log.info("【入侵告警】请求AG响应:{}", resultEvent);
+
+                        if (StrUtil.isNotBlank(resultEvent)) {
+                            AlarmEventInfoVo eventInfoVo = mapper.readValue(resultEvent, AlarmEventInfoVo.class);
+                            if (eventInfoVo != null && eventInfoVo.getResult() != null && eventInfoVo.getResult().getEventInfo() != null) {
+                                // HTTP获取成功,使用详细信息处理
+                                AlarmEventInfo eventInfo = eventInfoVo.getResult().getEventInfo();
+                                processAlarmEventWithHttpInfo(eventInfo, root, id);
+                                return;
+                            }
+                        }
+                    } catch (Exception httpEx) {
+                        log.warn("【入侵告警】HTTP获取详细信息失败,降级到MQTT处理:{}", httpEx.getMessage());
+                        // 降级到MQTT处理
+                    }
+                }
+                
+                // MQTT基础处理(降级方案)
+                log.info("【入侵告警】使用MQTT基础信息处理");
                 Integer channel = root.path("channel").asInt();
-                Integer eventCode = root.path("code").asInt(); // 真实消息里是 code 字段!
-                String id = root.path("id").asText();
-                String triggerTime = root.path("triggerTime").asText();
+                Integer eventCode = root.path("code").asInt();
+                String triggerTime = root.path("triggerTime").asText(); 
                 String note = root.path("note").asText();
                 Integer eventSystem = root.path("eventSystem").asInt();
 
-                // 打印日志,确认字段都读到了
-                log.info("【入侵告警】收到消息:deviceId={}, channel={}, eventCode={}, id={}",
-                        deviceId, channel, eventCode, id);
-
                 // 设备校验
                 SasDevice device = findDevice(deviceId, SystemTypeCodeEnum.alarm.getCode());
                 if (device == null) {
@@ -812,6 +766,25 @@ public class MqttService {
                 event.setCreateTime(LocalDateTime.now());
                 event.setUpdateTime(LocalDateTime.now());
 
+                // 【新增】处理图片信息
+                if (root.path("alarmPic") != null && !root.path("alarmPic").isMissingNode()) {
+                    JsonNode picNode = root.path("alarmPic");
+                    String picUrl = picNode.path("url").asText();
+                    String picPath = picNode.path("path").asText();
+                    
+                    if (StrUtil.isNotBlank(picUrl) && StrUtil.isNotBlank(picPath)) {
+                        SasPic pic = new SasPic();
+                        pic.setId(IdUtil.randomUUID());
+                        pic.setUrl(picUrl);
+                        pic.setPath(picPath);
+                        pic.setCreateTime(LocalDateTime.now());
+                        pic.setUpdateTime(LocalDateTime.now());
+                        sasPicMapper.insert(pic);
+                        event.setPicId(pic.getId());
+                        log.debug("【入侵告警】图片保存成功,picId={}", pic.getId());
+                    }
+                }
+
                 // 保存到数据库
                 alarsasEventService.save(event);
                 log.info("【入侵告警】保存成功!eventId={}, deviceId={}, eventCode={}",
@@ -822,6 +795,15 @@ public class MqttService {
                 info.setTriggerTime(triggerTime);
                 info.setCreateTime(LocalDateTime.now().format(formatter));
 
+                // 【新增】设置图片URL(如果有)
+                if (event.getPicId() != null) {
+                    SasPic pic = sasPicMapper.selectById(event.getPicId());
+                    if (pic != null && StrUtil.isNotBlank(pic.getUrl()) && StrUtil.isNotBlank(pic.getPath())) {
+                        info.setEventUrl(pic.getUrl() + pic.getPath());
+                        log.debug("【入侵告警】图片URL设置成功:{}", info.getEventUrl());
+                    }
+                }
+
                 SasAlarsasEventCode code = alarsasEventCodeMapper.selectById(eventCode);
                 if (code != null) {
                     info.setEventTypeName(code.getName());
@@ -1151,12 +1133,23 @@ public class MqttService {
                 info.setTriggerTime(message.getTriggerTime());
                 info.setCreateTime(LocalDateTime.now().format(formatter));
 
-                if (message.getEventPicInfo() != null) {
-                    info.setEventUrl(message.getEventPicInfo().getUrl() + message.getEventPicInfo().getPath());
+                // 【修复】从数据库中获取图片URL,确保一致性
+                if (event.getPicId() != null) {
+                    SasPic eventPic = sasPicMapper.selectById(event.getPicId());
+                    if (eventPic != null && StrUtil.isNotBlank(eventPic.getUrl()) && StrUtil.isNotBlank(eventPic.getPath())) {
+                        info.setEventUrl(eventPic.getUrl() + eventPic.getPath());
+                    }
                 }
-
-                if (message.getScenePicInfo() != null) {
-                    info.setEventUrl(message.getScenePicInfo().getUrl() + message.getScenePicInfo().getPath());
+                
+                if (event.getScenePicId() != null) {
+                    SasPic scenePic = sasPicMapper.selectById(event.getScenePicId());
+                    if (scenePic != null && StrUtil.isNotBlank(scenePic.getUrl()) && StrUtil.isNotBlank(scenePic.getPath())) {
+                        // 如果还没有事件URL,使用场景图片
+                        if (info.getEventUrl() == null) {
+                            info.setEventUrl(scenePic.getUrl() + scenePic.getPath());
+                        }
+                        info.setSceneUrl(scenePic.getUrl() + scenePic.getPath());
+                    }
                 }
 
                 SasCollectionEventCode code = collectionEventCodeMapper.selectById(event.getEventCode());
@@ -1291,6 +1284,81 @@ public class MqttService {
         }
     }
 
+    /**
+     * 使用HTTP获取的详细信息处理入侵告警事件
+     */
+    private void processAlarmEventWithHttpInfo(AlarmEventInfo eventInfo, JsonNode mqttRoot, String id) {
+        try {
+            SasDevice device = findDevice(eventInfo.getDeviceId(), SystemTypeCodeEnum.alarm.getCode());
+            if (device == null) {
+                log.warn("【入侵告警-HTTP】设备不存在,丢弃事件:deviceId={}", eventInfo.getDeviceId());
+                return;
+            }
+
+            String eventId = StrUtil.isNotBlank(id) ? id : IdUtil.randomUUID();
+            if (alarsasEventService.getById(eventId) != null) {
+                log.info("【入侵告警-HTTP】事件已存在,跳过保存:eventId={}", eventId);
+                return;
+            }
+
+            SasAlarsasEvent event = new SasAlarsasEvent();
+            event.setEventId(eventId);
+            
+            // 从HTTP响应中获取详细信息
+            BeanUtil.copyProperties(eventInfo, event);
+            event.setEventSystem(eventInfo.getSystemCode());
+            event.setTriggerTime(parseTime(eventInfo.getTriggerTime()));
+            event.setCreateTime(LocalDateTime.now());
+            event.setUpdateTime(LocalDateTime.now());
+
+            // 处理HTTP中的图片信息
+            if (eventInfo.getEventPic() != null) {
+                SasPic pic = BeanUtil.toBean(eventInfo.getEventPic(), SasPic.class);
+                pic.setId(IdUtil.randomUUID());
+                pic.setCreateTime(LocalDateTime.now());
+                pic.setUpdateTime(LocalDateTime.now());
+                sasPicMapper.insert(pic);
+                event.setPicId(pic.getId());
+                log.debug("【入侵告警-HTTP】图片保存成功,picId={}", pic.getId());
+            }
+
+            // 保存到数据库
+            alarsasEventService.save(event);
+            log.info("【入侵告警-HTTP】保存成功!eventId={}, deviceId={}, eventCode={}",
+                    eventId, eventInfo.getDeviceId(), eventInfo.getEventCode());
+
+            // WebSocket推送
+            BrieflyEventInfo info = BeanUtil.toBean(event, BrieflyEventInfo.class);
+            info.setTriggerTime(eventInfo.getTriggerTime());
+            info.setCreateTime(LocalDateTime.now().format(formatter));
+
+            // 设置图片URL
+            if (event.getPicId() != null) {
+                SasPic pic = sasPicMapper.selectById(event.getPicId());
+                if (pic != null && StrUtil.isNotBlank(pic.getUrl()) && StrUtil.isNotBlank(pic.getPath())) {
+                    info.setEventUrl(pic.getUrl() + pic.getPath());
+                    log.debug("【入侵告警-HTTP】图片URL设置成功:{}", info.getEventUrl());
+                }
+            }
+
+            SasAlarsasEventCode code = alarsasEventCodeMapper.selectById(eventInfo.getEventCode());
+            if (code != null) {
+                info.setEventTypeName(code.getName());
+            }
+
+            enrichDeviceInfo(info, device);
+            SasEventTypeGroup eventTypeGroup = findEventTypeGroup(SystemTypeCodeEnum.alarm.getCode());
+            if (eventTypeGroup != null) {
+                info.setEventLevelId(eventTypeGroup.getEventLevel());
+            }
+            info.setDeviceType(SystemTypeCodeEnum.alarm.getCode());
+            SasWebSocket.sendAll(info);
+
+        } catch (Exception e) {
+            log.error("【入侵告警-HTTP】处理失败", e);
+        }
+    }
+
     @PreDestroy
     public void disconnect() {
         try {
@@ -1307,4 +1375,181 @@ public class MqttService {
         }
     }
 
+    /**
+     * 使用HTTP获取的详细信息处理车辆抓拍事件
+     */
+    private void processParkingEventWithHttpInfo(ParkingEventInfo eventInfo, ParkingEventResult eventResult) {
+        try {
+            SasDevice device = findDevice(eventInfo.getDeviceId(), SystemTypeCodeEnum.parking.getCode());
+            if (device == null) {
+                log.warn("【车辆抓拍-HTTP】设备不存在,丢弃事件:deviceId={}", eventInfo.getDeviceId());
+                return;
+            }
+
+            String eventId = StrUtil.isNotBlank(eventResult.getId()) ? eventResult.getId() : IdUtil.randomUUID();
+            if (parkingEventService.getById(eventId) != null) {
+                log.info("【车辆抓拍-HTTP】事件已存在,跳过保存:eventId={}", eventId);
+                return;
+            }
+
+            // 处理图片信息
+            String eventPicId = null;
+            String platePicId = null;
+            
+            if (eventInfo.getEventPic() != null) {
+                try {
+                    SasPic eventPic = BeanUtil.toBean(eventInfo.getEventPic(), SasPic.class);
+                    eventPic.setId(IdUtil.randomUUID());
+                    eventPic.setCreateTime(LocalDateTime.now());
+                    eventPic.setUpdateTime(LocalDateTime.now());
+                    sasPicMapper.insert(eventPic);
+                    eventPicId = eventPic.getId();
+                    log.info("【车辆抓拍-HTTP】事件图片保存成功,eventPicId={}", eventPicId);
+                } catch (Exception e) {
+                    log.error("【车辆抓拍-HTTP】事件图片保存失败", e);
+                    throw e;
+                }
+            }
+
+            if (eventInfo.getPlacePic() != null) {
+                try {
+                    SasPic platePic = BeanUtil.toBean(eventInfo.getPlacePic(), SasPic.class);
+                    platePic.setId(IdUtil.randomUUID());
+                    platePic.setCreateTime(LocalDateTime.now());
+                    platePic.setUpdateTime(LocalDateTime.now());
+                    sasPicMapper.insert(platePic);
+                    platePicId = platePic.getId();
+                    log.info("【车辆抓拍-HTTP】车牌图片保存成功,platePicId={}", platePicId);
+                } catch (Exception e) {
+                    log.error("【车辆抓拍-HTTP】车牌图片保存失败", e);
+                    throw e;
+                }
+            }
+
+            SasParkingEvent event = new SasParkingEvent();
+            event.setEventId(eventId);
+            // 排除可能产生冲突的字段,避免被覆盖
+            BeanUtil.copyProperties(eventInfo, event, "eventPicId", "platePicId", "createTime", "updateTime");
+            event.setEventPicId(eventPicId);
+            event.setPlatePicId(platePicId);
+            event.setTriggerTime(parseTime(eventInfo.getTriggerTime()));
+            // event.setReceivingTime(parseTime(eventInfo.getReceivingTime())); // 不存在此字段
+            event.setCreateTime(LocalDateTime.now());
+            event.setUpdateTime(LocalDateTime.now());
+
+            // 确保关键字段不被覆盖
+            event.setAccessType(eventInfo.getIo());
+            event.setCarType(eventInfo.getCarCode());
+            event.setPlateType(eventInfo.getPlateCode());
+
+            parkingEventService.save(event);
+            log.info("【车辆抓拍-HTTP】保存成功!eventId={}, deviceId={}, eventCode={}",
+                    eventId, eventInfo.getDeviceId(), eventInfo.getEventCode());
+
+            // WebSocket推送
+            BrieflyEventInfo info = BeanUtil.toBean(event, BrieflyEventInfo.class);
+            info.setTriggerTime(eventInfo.getTriggerTime());
+            info.setCreateTime(LocalDateTime.now().format(formatter));
+
+            // 设置图片URL
+            if (event.getEventPicId() != null) {
+                SasPic eventPic = sasPicMapper.selectById(event.getEventPicId());
+                if (eventPic != null && StrUtil.isNotBlank(eventPic.getUrl()) && StrUtil.isNotBlank(eventPic.getPath())) {
+                    info.setEventUrl(eventPic.getUrl() + eventPic.getPath());
+                    log.debug("【车辆抓拍-HTTP】事件图片URL设置成功:{}", info.getEventUrl());
+                }
+            }
+            if (event.getPlatePicId() != null) {
+                SasPic platePic = sasPicMapper.selectById(event.getPlatePicId());
+                if (platePic != null && StrUtil.isNotBlank(platePic.getUrl()) && StrUtil.isNotBlank(platePic.getPath())) {
+                    if (info.getEventUrl() == null) {
+                        info.setEventUrl(platePic.getUrl() + platePic.getPath());
+                    }
+                    info.setSceneUrl(platePic.getUrl() + platePic.getPath());
+                    log.debug("【车辆抓拍-HTTP】车牌图片URL设置成功:{}", info.getSceneUrl());
+                }
+            }
+
+            SasParkingEventCode code = parkingEventCodeMapper.selectById(event.getEventCode());
+            if (code != null) {
+                info.setEventTypeName(code.getName());
+            }
+
+            enrichDeviceInfo(info, device);
+            SasEventTypeGroup eventTypeGroup = findEventTypeGroup(SystemTypeCodeEnum.parking.getCode());
+            if (eventTypeGroup != null) {
+                info.setEventLevelId(eventTypeGroup.getEventLevel());
+            }
+            info.setDeviceType(SystemTypeCodeEnum.parking.getCode());
+            SasWebSocket.sendAll(info);
+
+        } catch (Exception e) {
+            log.error("【车辆抓拍-HTTP】处理失败", e);
+        }
+    }
+
+    /**
+     * 使用MQTT基础信息处理车辆抓拍事件(降级方案)
+     */
+    private void processParkingEventWithMqttInfo(ParkingEventResult eventResult, JsonNode mqttRoot) {
+        try {
+            // 从MQTT消息中获取设备信息
+            String deviceId = mqttRoot.path("deviceId").asText();
+            if (StrUtil.isBlank(deviceId)) {
+                log.warn("【车辆抓拍-MQTT】MQTT消息中没有deviceId,丢弃事件");
+                return;
+            }
+            
+            SasDevice device = findDevice(deviceId, SystemTypeCodeEnum.parking.getCode());
+            if (device == null) {
+                log.warn("【车辆抓拍-MQTT】设备不存在,丢弃事件:deviceId={}", deviceId);
+                return;
+            }
+
+            String eventId = StrUtil.isNotBlank(eventResult.getId()) ? eventResult.getId() : IdUtil.randomUUID();
+            if (parkingEventService.getById(eventId) != null) {
+                log.info("【车辆抓拍-MQTT】事件已存在,跳过保存:eventId={}", eventId);
+                return;
+            }
+
+            SasParkingEvent event = new SasParkingEvent();
+            event.setEventId(eventId);
+            event.setDeviceId(deviceId);
+            event.setEventCode(mqttRoot.path("code").asInt());
+            event.setTriggerTime(parseTime(mqttRoot.path("triggerTime").asText()));
+            event.setCreateTime(LocalDateTime.now());
+            event.setUpdateTime(LocalDateTime.now());
+
+            // MQTT基础信息不包含详细图片,需要设置为null
+            event.setEventPicId(null);
+            event.setPlatePicId(null);
+
+            parkingEventService.save(event);
+            log.info("【车辆抓拍-MQTT】保存成功!eventId={}, deviceId={}, eventCode={}",
+                    eventId, deviceId, event.getEventCode());
+
+            // WebSocket推送
+            BrieflyEventInfo info = BeanUtil.toBean(event, BrieflyEventInfo.class);
+            info.setTriggerTime(mqttRoot.path("triggerTime").asText());
+            info.setCreateTime(LocalDateTime.now().format(formatter));
+            // MQTT模式下图片URL为空
+
+            SasParkingEventCode code = parkingEventCodeMapper.selectById(event.getEventCode());
+            if (code != null) {
+                info.setEventTypeName(code.getName());
+            }
+
+            enrichDeviceInfo(info, device);
+            SasEventTypeGroup eventTypeGroup = findEventTypeGroup(SystemTypeCodeEnum.parking.getCode());
+            if (eventTypeGroup != null) {
+                info.setEventLevelId(eventTypeGroup.getEventLevel());
+            }
+            info.setDeviceType(SystemTypeCodeEnum.parking.getCode());
+            SasWebSocket.sendAll(info);
+
+        } catch (Exception e) {
+            log.error("【车辆抓拍-MQTT】处理失败", e);
+        }
+    }
+
 }