diff --git a/jsowell-admin/src/main/java/com/jsowell/service/CameraService.java b/jsowell-admin/src/main/java/com/jsowell/service/CameraService.java index e84faa887..90a0da686 100644 --- a/jsowell-admin/src/main/java/com/jsowell/service/CameraService.java +++ b/jsowell-admin/src/main/java/com/jsowell/service/CameraService.java @@ -3,7 +3,9 @@ package com.jsowell.service; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.jsowell.common.constant.CacheConstants; +import com.jsowell.common.constant.Constants; import com.jsowell.common.core.redis.RedisCache; +import com.jsowell.common.enums.uniapp.OccupyOrderStatusEnum; import com.jsowell.common.util.DateUtils; import com.jsowell.common.util.StringUtils; import com.jsowell.common.util.file.AliyunOssUploadUtils; @@ -12,6 +14,7 @@ import com.jsowell.common.util.sign.MD5Util; import com.jsowell.netty.server.mqtt.BootNettyMqttChannelInboundHandler; import com.jsowell.pile.domain.OrderPileOccupy; import com.jsowell.pile.domain.PileCameraInfo; +import com.jsowell.pile.dto.GenerateOccupyOrderDTO; import com.jsowell.pile.dto.camera.Camera2GroundLockCommand; import com.jsowell.pile.dto.camera.CameraHeartBeatDTO; import com.jsowell.pile.dto.camera.CameraIdentifyResultsDTO; @@ -30,11 +33,10 @@ import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.Base64; +import java.util.*; import javax.imageio.ImageIO; -import java.util.List; -import java.util.Locale; +import java.util.concurrent.TimeUnit; /** * 相机管理系统 Service @@ -93,48 +95,21 @@ public class CameraService { * * @param jsonObject */ - private void vehicleEntry(JSONObject jsonObject, String parkingState) throws InterruptedException { + private String vehicleEntry(JSONObject jsonObject, String parkingState) throws InterruptedException { // 先将车牌图片信息存入缓存 // boolean result = saveCarPicture2Redis(jsonObject, parkingState); - // 解析 jsonObject - // 车牌信息 - CameraIdentifyResultsDTO.ProductH.Plate plate = JSONObject.parseObject(jsonObject.getJSONObject("product_h").getJSONObject("plate").toJSONString(), - CameraIdentifyResultsDTO.ProductH.Plate.class); - if (plate == null) { - return; - } - // 设备信息 - CameraIdentifyResultsDTO.DeviceInfo deviceInfo = JSONObject.parseObject(jsonObject.getJSONObject("device_info").toJSONString(), - CameraIdentifyResultsDTO.DeviceInfo.class); - if (deviceInfo == null) { - return; - } - // 停车位信息 - CameraIdentifyResultsDTO.ProductH.Parking parking = JSONObject.parseObject(jsonObject.getJSONObject("product_h").getJSONObject("parking").toJSONString(), - CameraIdentifyResultsDTO.ProductH.Parking.class); - if (parking == null) { - return; - } - // 获取背景图片 - JSONArray bgImgs = jsonObject.getJSONArray("bg_img"); - List bgImgList = bgImgs.toList(CameraIdentifyResultsDTO.BgImg.class); - if (CollectionUtils.isEmpty(bgImgList)) { - return; - } - // Base64 解密 - String plateNumber = cn.hutool.core.codec.Base64.decodeStr(plate.getPlate()); - String zoneName = cn.hutool.core.codec.Base64.decodeStr(parking.getZoneName()); - // 将解密后的值重新 set 进对象中,便于存储数据库 - plate.setPlate(plateNumber); - parking.setZoneName(zoneName); - // 将信息存数据库 - boolean result = saveInfo2DataBase(bgImgList, plate, deviceInfo, parking); - if (!result) { + Map resultMap = saveInfo2DataBase(jsonObject); + if (resultMap == null) { logger.error("车辆入场,将信息存入数据库 error, 源数据:{}", jsonObject); - return; + return null; } + String sn = resultMap.get("sn"); + String zoneId = resultMap.get("zoneId"); + String plateNumber = resultMap.get("plateNumber"); + String devName = resultMap.get("devName"); + // 先判断该车牌是否有挂起未支付的占桩订单 OrderPileOccupy occupy = OrderPileOccupy.builder() .status("2") // 2-订单挂起 @@ -143,52 +118,94 @@ public class CameraService { List occupyList = orderPileOccupyService.getOrderPileOccupyList(occupy); // todo 如果有占桩订单,则先提醒“需支付占桩订单” if (CollectionUtils.isNotEmpty(occupyList)) { - return; + return "需支付占桩订单"; } // 根据车牌号找出绑定小程序的用户 List memberList = memberBasicInfoService.getMemberInfoByPlateNumber(plateNumber); + GenerateOccupyOrderDTO dto = new GenerateOccupyOrderDTO(); + dto.setPileSn(devName); // TODO + dto.setConnectorCode(String.valueOf(zoneId)); // TODO + dto.setOrderStatus(OccupyOrderStatusEnum.ORDER_HANG_UP.getCode()); // 订单挂起 + dto.setPayStatus(Constants.ZERO); // 未支付 + String occupyPileOrderCode = null; if (CollectionUtils.isNotEmpty(memberList)) { // 如果是有小程序的用户,则先降地锁,然后生成一笔占桩订单 // 发送降锁指令 - Camera2GroundLockCommand command = Camera2GroundLockCommand.builder() - .sn(deviceInfo.getSn()) - .msgType("GroundlockOption") - .msgPrefix("GO") - .topic("/remoteCommand") - .zoneId(parking.getZoneId()) - .option(3) // 3-降锁后不自动升锁 - .force(0) // 强制操作 0:否 1:是 - - .build(); - String msgId = sendGroundLockMsg(command); - // 判断降锁是否成功 - String redisKey = "plate_number_occupy_order:" + msgId; - - - // 降锁成功,生成占桩订单(挂起、未支付) - - } else { + Object cacheObject = sendGroundLockMsg(sn, Integer.parseInt(zoneId)); + if (cacheObject != null) { + // 降锁成功,生成占桩订单(挂起、未支付) + dto.setMemberId(memberList.get(0).getMemberId()); + occupyPileOrderCode = orderPileOccupyService.generateOccupyPileOrder(dto); + } + }else { // 如果没有小程序账号,再根据此车牌是否有挂起的占桩订单 - - // 如果没有,则先降锁,再生成一笔占桩订单 - - // 如果有已挂起的占桩订单,则不予降锁,将“已存在有未支付的占桩订单”信息返回 - + OrderPileOccupy orderPileOccupy = new OrderPileOccupy(); + orderPileOccupy.setPlateNumber(plateNumber); + List orderPileOccupyList = orderPileOccupyService.getOrderPileOccupyList(orderPileOccupy); + // TODO 如果有已挂起的占桩订单,则不予降锁,将“已存在有未支付的占桩订单”信息返回 + if (CollectionUtils.isNotEmpty(orderPileOccupyList)) { + return "已存在有未支付的占桩订单"; + } + // 如果没有,则先降锁,再生成一笔占桩订单 (与车牌号绑定) + Object cacheObject = sendGroundLockMsg(sn, Integer.parseInt(zoneId)); + if (cacheObject == null) { + return null; + } + dto.setPlateNumber(plateNumber); + occupyPileOrderCode = orderPileOccupyService.generateOccupyPileOrder(dto); } - - - // TODO 生成占桩订单 - // GenerateOccupyOrderDTO dto = new GenerateOccupyOrderDTO(); - // dto.setMemberId(); - // dto.setPileSn(); - // dto.setConnectorCode(); - // orderPileOccupyService.generateOccupyPileOrder() + return occupyPileOrderCode; } - private boolean saveInfo2DataBase(List bgImgList, CameraIdentifyResultsDTO.ProductH.Plate plate, - CameraIdentifyResultsDTO.DeviceInfo deviceInfo, CameraIdentifyResultsDTO.ProductH.Parking parking) { - String zoneName = parking.getZoneName(); + /** + * 对数据进行解析并存储到数据库 + * @param jsonObject + * @return + */ + private Map saveInfo2DataBase(JSONObject jsonObject) { + Map resultMap = new LinkedHashMap<>(); + // 解析 jsonObject + // 车牌信息 + CameraIdentifyResultsDTO.ProductH.Plate plate = JSONObject.parseObject(jsonObject.getJSONObject("product_h") + .getJSONObject("plate").toJSONString(), + CameraIdentifyResultsDTO.ProductH.Plate.class); + if (plate == null) { + logger.error("车位相机解析 error, 车牌信息为空"); + return null; + } + // 设备信息 + CameraIdentifyResultsDTO.DeviceInfo deviceInfo = JSONObject.parseObject(jsonObject.getJSONObject("device_info").toJSONString(), + CameraIdentifyResultsDTO.DeviceInfo.class); + if (deviceInfo == null) { + logger.error("车位相机解析 error, 设备信息为空"); + return null; + } + // 停车位信息 + CameraIdentifyResultsDTO.ProductH.Parking parking = JSONObject.parseObject(jsonObject.getJSONObject("product_h") + .getJSONObject("parking").toJSONString(), + CameraIdentifyResultsDTO.ProductH.Parking.class); + if (parking == null) { + logger.error("车位相机解析 error, 停车位信息为空"); + return null; + } + // 获取背景图片 + JSONArray bgImgs = jsonObject.getJSONArray("bg_img"); + List bgImgList = bgImgs.toList(CameraIdentifyResultsDTO.BgImg.class); + if (CollectionUtils.isEmpty(bgImgList)) { + logger.error("车位相机解析 error, 背景图片信息为空"); + return null; + } + String sn = deviceInfo.getSn(); + Integer zoneId = parking.getZoneId(); + String devName = deviceInfo.getDevName(); + // Base64 解密 + String plateNumber = cn.hutool.core.codec.Base64.decodeStr(plate.getPlate()); + String zoneName = cn.hutool.core.codec.Base64.decodeStr(parking.getZoneName()); + // 将解密后的值重新 set 进对象中,便于存储数据库 + plate.setPlate(plateNumber); + parking.setZoneName(zoneName); + // 循环 bgImgList, 将图片分成单张进行存储 for (CameraIdentifyResultsDTO.BgImg bgImg : bgImgList) { // 上传到阿里云OSS,获取图片上传成功后的地址 String fileName = zoneName + "-" + System.currentTimeMillis() / 1000 + ".jpg"; @@ -198,12 +215,12 @@ public class CameraService { continue; } PileCameraInfo pileCameraInfo = PileCameraInfo.builder() - .deviceName(deviceInfo.getDevName()) + .deviceName(devName) .deviceIp(deviceInfo.getIp()) - .deviceSn(deviceInfo.getSn()) - .plateNumber(plate.getPlate()) + .deviceSn(sn) + .plateNumber(plateNumber) .parkingState(String.valueOf(parking.getParkingState())) - .zoneId(parking.getZoneId()) + .zoneId(zoneId) .zoneName(zoneName) .color(plate.getColor()) .plateType(plate.getType()) @@ -213,8 +230,12 @@ public class CameraService { // 插入数据库 pileCameraInfoService.insertPileCameraInfo(pileCameraInfo); } - - return true; + // 构建返回参数 + resultMap.put("sn", sn); + resultMap.put("zoneId", String.valueOf(zoneId)); + resultMap.put("plateNumber", plateNumber); + resultMap.put("devName", devName); + return resultMap; } @@ -255,16 +276,40 @@ public class CameraService { /** * 发送地锁升降指令 + * @param sn 相机的sn号 + * @param zoneId 相机对应的车位id + * @return 发送降锁指令的响应对象 + * @throws InterruptedException */ - private String sendGroundLockMsg(Camera2GroundLockCommand command) throws InterruptedException { + private Object sendGroundLockMsg(String sn, Integer zoneId) throws InterruptedException { + Camera2GroundLockCommand command = Camera2GroundLockCommand.builder() + .sn(sn) + .msgType("GroundlockOption") + .msgPrefix("GO") + .topic("/remoteCommand") + .zoneId(zoneId) + .option(3) // 3-降锁后不自动升锁 + .force(0) // 强制操作 0:否 1:是 + .build(); JSONObject msgData = new JSONObject(); msgData.put("option", command.getOption()); msgData.put("zone_id", command.getZoneId()); msgData.put("force", command.getForce()); String msgId = sendMsg2Topic(command.getSn(), command.getMsgType(), command.getMsgPrefix(), command.getTopic(), msgData); - return msgId; + + // 判断降锁是否成功 + // 将此降锁指令存入缓存, 在 nettyServer 收到新消息时判断是否是此消息的回复 + String redisKey = "plate_number_occupy_order:" + msgId; + redisCache.setCacheObject(redisKey, command, 5, TimeUnit.MINUTES); + + // 延时 3 秒钟, 再查询缓存中是否有此降锁信息的回复 + Thread.sleep(3); + + String responseRedisKey = "plate_number_occupy_order_response:" + msgId; + Object cacheObject = redisCache.getCacheObject(responseRedisKey); + return cacheObject; } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/dto/GenerateOccupyOrderDTO.java b/jsowell-pile/src/main/java/com/jsowell/pile/dto/GenerateOccupyOrderDTO.java index 8e3393375..0a3f082de 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/dto/GenerateOccupyOrderDTO.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/dto/GenerateOccupyOrderDTO.java @@ -21,4 +21,25 @@ public class GenerateOccupyOrderDTO { * 枪口号 */ private String connectorCode; + + + /** + * 下面参数非必传 + */ + + + /** + * 订单状态 + */ + private String orderStatus; + + /** + * 支付状态 + */ + private String payStatus; + + /** + * 车牌号 + */ + private String plateNumber; } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderPileOccupyServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderPileOccupyServiceImpl.java index 2247fd2ed..df30dbd13 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderPileOccupyServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderPileOccupyServiceImpl.java @@ -180,6 +180,17 @@ public class OrderPileOccupyServiceImpl implements OrderPileOccupyService { String pileSn = dto.getPileSn(); String connectorCode = dto.getConnectorCode(); + String orderStatus = dto.getOrderStatus(); + String payStatus = dto.getPayStatus(); + String plateNumber = dto.getPlateNumber(); + + if (StringUtils.isBlank(orderStatus)) { + orderStatus = OccupyOrderStatusEnum.DRAFT_ORDER.getCode(); // 草稿单 + } + if (StringUtils.isBlank(payStatus)) { + payStatus = Constants.TWO; // 无需支付 + } + String redisKey = CacheConstants.GROUND_LOCK_OCCUPY_ORDER + pileSn + connectorCode; String cacheObject = redisCache.getCacheObject(redisKey); if (StringUtils.isNotBlank(cacheObject)) { @@ -191,8 +202,11 @@ public class OrderPileOccupyServiceImpl implements OrderPileOccupyService { String occupyCode = "OP" + IdUtils.getOrderCode(); orderPileOccupy.setOccupyCode(occupyCode); orderPileOccupy.setMemberId(memberId); - orderPileOccupy.setStatus(OccupyOrderStatusEnum.DRAFT_ORDER.getCode()); // 草稿单 - orderPileOccupy.setPayStatus(Constants.TWO); // 无需支付 + orderPileOccupy.setStatus(orderStatus); // 草稿单 + orderPileOccupy.setPayStatus(payStatus); // 无需支付 + if (StringUtils.isNotBlank(plateNumber)) { + orderPileOccupy.setPlateNumber(plateNumber); // 车牌号 + } orderPileOccupy.setPileSn(pileSn); PileInfoVO pileInfoVO = pileBasicInfoService.selectPileInfoBySn(pileSn); if (pileInfoVO != null) { diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/huawei/HuaweiServiceV2.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/huawei/HuaweiServiceV2.java index 4001f1f77..d541c7d43 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/huawei/HuaweiServiceV2.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/huawei/HuaweiServiceV2.java @@ -92,9 +92,6 @@ public class HuaweiServiceV2 { @Autowired private OrderBasicInfoService orderBasicInfoService; - @Autowired - private ThirdPartyStationRelationService thirdPartyStationRelationService; - @Autowired private MemberPlateNumberRelationService memberPlateNumberRelationService; @@ -725,6 +722,7 @@ public class HuaweiServiceV2 { orderBasicInfo.setChargeStartTime(DateUtils.parseDate(dto.getStartTime())); orderBasicInfo.setChargeEndTime(DateUtils.parseDate(dto.getEndTime())); + orderBasicInfo.setOrderStatus(OrderStatusEnum.ORDER_COMPLETE.getValue()); // 订单状态改为订单完成 orderBasicInfo.setReason(String.valueOf(dto.getStopReason())); // TODO 新建停止原因枚举 orderDetail.setTotalUsedElectricity(dto.getTotalPower());