diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/device/domain/Device.java b/ruoyi-service/src/main/java/com/ruoyi/bst/device/domain/Device.java index c2b25a0..ce25f43 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/device/domain/Device.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/device/domain/Device.java @@ -155,6 +155,10 @@ public class Device extends BaseEntity implements IotDevice, LogBizParam @ApiModelProperty("最近一次下单用户ID") private Long lastUserId; + @Excel(name = "定位类型") + @ApiModelProperty("定位类型(1设备定位 2手机定位)") + private String locationType; + @Override public String mac() { return this.mac; diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/device/domain/dto/DeviceBltUploadDTO.java b/ruoyi-service/src/main/java/com/ruoyi/bst/device/domain/dto/DeviceBltUploadDTO.java new file mode 100644 index 0000000..2d55a14 --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/device/domain/dto/DeviceBltUploadDTO.java @@ -0,0 +1,21 @@ +package com.ruoyi.bst.device.domain.dto; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import com.ruoyi.iot.domain.IotDeviceSysInfo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class DeviceBltUploadDTO { + + @ApiModelProperty("设备MAC") + @NotBlank(message = "设备MAC不能为空") + private String mac; + + @ApiModelProperty("系统数据") + @NotNull(message = "系统数据不能为空") + private IotDeviceSysInfo sys; +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/device/domain/enums/DeviceLocationType.java b/ruoyi-service/src/main/java/com/ruoyi/bst/device/domain/enums/DeviceLocationType.java new file mode 100644 index 0000000..6658f6e --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/device/domain/enums/DeviceLocationType.java @@ -0,0 +1,15 @@ +package com.ruoyi.bst.device.domain.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum DeviceLocationType { + DEVICE("1", "设备定位"), + PHONE("2", "手机定位"); + + private String code; + private String name; + +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/device/mapper/DeviceMapper.xml b/ruoyi-service/src/main/java/com/ruoyi/bst/device/mapper/DeviceMapper.xml index 0326c3d..6d8735d 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/device/mapper/DeviceMapper.xml +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/device/mapper/DeviceMapper.xml @@ -44,6 +44,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" bd.last_online_time, bd.order_device_id, bd.software_version, + bd.location_type, mch.nick_name as mch_name, mch.point as mch_point, bm.name as model_name, @@ -129,6 +130,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and suo.user_name like concat('%', #{query.orderUserPhone}, '%') and bd.last_location_time <= #{query.lastTimeEnd} and bd.last_location_time >= #{query.lastTimeStart} + and bd.location_type = #{query.locationType} and ( bd.sn like concat('%', #{query.keyword}, '%') @@ -234,6 +236,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" last_online_time, order_device_id, software_version, + location_type, #{modelId}, @@ -268,6 +271,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{lastOnlineTime}, #{orderDeviceId}, #{softwareVersion}, + #{locationType}, @@ -312,6 +316,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" bd.last_online_time = #{data.lastOnlineTime}, bd.order_device_id = #{data.orderDeviceId}, bd.software_version = #{data.softwareVersion}, + bd.location_type = #{data.locationType}, diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/device/service/DeviceIotService.java b/ruoyi-service/src/main/java/com/ruoyi/bst/device/service/DeviceIotService.java index 531f752..6d7493a 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/device/service/DeviceIotService.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/device/service/DeviceIotService.java @@ -5,6 +5,7 @@ import java.util.List; import com.ruoyi.bst.device.domain.Device; import com.ruoyi.bst.device.domain.DeviceVO; +import com.ruoyi.bst.device.domain.dto.DeviceBltUploadDTO; import com.ruoyi.bst.device.domain.enums.DeviceUnLockType; import com.ruoyi.bst.device.domain.vo.DeviceIotVO; @@ -146,4 +147,11 @@ public interface DeviceIotService { */ int updateIot(Device device); + /** + * 蓝牙上传 + * @param dto + * @return + */ + int bltUpload(DeviceBltUploadDTO dto); + } diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/device/service/impl/DeviceIotServiceImpl.java b/ruoyi-service/src/main/java/com/ruoyi/bst/device/service/impl/DeviceIotServiceImpl.java index 9c4f0ce..5ce2489 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/device/service/impl/DeviceIotServiceImpl.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/device/service/impl/DeviceIotServiceImpl.java @@ -14,6 +14,8 @@ import org.springframework.transaction.support.TransactionTemplate; import com.ruoyi.bst.device.domain.Device; import com.ruoyi.bst.device.domain.DeviceQuery; import com.ruoyi.bst.device.domain.DeviceVO; +import com.ruoyi.bst.device.domain.dto.DeviceBltUploadDTO; +import com.ruoyi.bst.device.domain.enums.DeviceLocationType; import com.ruoyi.bst.device.domain.enums.DeviceLockStatus; import com.ruoyi.bst.device.domain.enums.DeviceQuality; import com.ruoyi.bst.device.domain.enums.DeviceStatus; @@ -23,8 +25,12 @@ import com.ruoyi.bst.device.mapper.DeviceMapper; import com.ruoyi.bst.device.service.DeviceIotService; import com.ruoyi.bst.device.service.DeviceService; import com.ruoyi.bst.device.utils.DeviceUtil; +import com.ruoyi.bst.locationLog.domain.LocationLog; +import com.ruoyi.bst.locationLog.service.LocationLogConverter; import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceStatus; +import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constants.ServiceCode; +import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisLock; import com.ruoyi.common.utils.MathUtils; import com.ruoyi.common.utils.ServiceUtil; @@ -59,9 +65,15 @@ public class DeviceIotServiceImpl implements DeviceIotService { @Autowired private ScheduledExecutorService scheduledExecutorService; + @Autowired + private LocationLogConverter locationLogConverter; + @Autowired private RedisLock redisLock; + @Autowired + private RedisCache redisCache; + private final static Integer SUB_FAST = 5; // 上报频率(快) private final static Integer SUB_SLOW = 300; // 上报频率(慢) @@ -275,7 +287,7 @@ public class DeviceIotServiceImpl implements DeviceIotService { } // 异步发送命令,强制设备上报数据 - scheduledExecutorService.schedule(() -> { + scheduledExecutorService.execute(() -> { for (DeviceVO device : deviceList) { try { if (onlineType != null) { @@ -285,7 +297,7 @@ public class DeviceIotServiceImpl implements DeviceIotService { log.error("强制设备{}上报数据失败", device.getSn(), e); } } - }, 0, TimeUnit.SECONDS); + }); } private void setOnlineStatus(DeviceVO device, String onlineStatus) { @@ -433,4 +445,27 @@ public class DeviceIotServiceImpl implements DeviceIotService { return vo; } + + @Override + public int bltUpload(DeviceBltUploadDTO dto) { + ServiceUtil.assertion(dto == null, "数据不能为空"); + + DeviceVO device = deviceService.selectByMac(dto.getMac()); + ServiceUtil.assertion(device == null, "设备不存在"); + + // 更新设备信息 + DeviceUtil.setIotSysInfo(device, dto.getSys(), LocalDateTime.now(), true); + device.setLocationType(DeviceLocationType.PHONE.getCode()); + int rows = this.updateIot(device); + + // 创建定位日志 + if (rows > 0) { + LocationLog locationLog = locationLogConverter.toPo(device); + if (locationLog != null) { + redisCache.rightPush(CacheConstants.LOCATION_LOG_QUEUE, locationLog); + } + } + + return rows; + } } diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/device/utils/DeviceUtil.java b/ruoyi-service/src/main/java/com/ruoyi/bst/device/utils/DeviceUtil.java index 8e4694a..fdefcdc 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/device/utils/DeviceUtil.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/device/utils/DeviceUtil.java @@ -5,6 +5,7 @@ import java.time.LocalDateTime; import java.util.List; import com.ruoyi.bst.device.domain.DeviceVO; +import com.ruoyi.bst.device.domain.enums.DeviceLocationType; import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceStatus; import com.ruoyi.common.utils.MathUtils; import com.ruoyi.common.utils.map.GpsCoordinateUtils; @@ -19,26 +20,26 @@ public class DeviceUtil { * @param device 设备 * @param sys 设备信息 */ - public static void setIotSysInfo(DeviceVO device, IotDeviceSysInfo sys, LocalDateTime at) { + public static void setIotSysInfo(DeviceVO device, IotDeviceSysInfo sys, LocalDateTime at, boolean setNull) { if (device == null || sys == null) { return; } // 转换经纬度坐标系并赋值 // 只有定位是正常的才认为是有获取到定位 - if (sys.getLon() != null && sys.getLat() != null - && !MathUtils.equals(sys.getLon(), BigDecimal.ZERO) - && !MathUtils.equals(sys.getLat(), BigDecimal.ZERO)) { + if (DeviceUtil.validLocation(sys.getLon(), sys.getLat())) { List coordinates = GpsCoordinateUtils.coordinateConvert(sys.getLon(), sys.getLat()); if (coordinates != null && coordinates.size() >= 2) { device.setLongitude(coordinates.get(1)); device.setLatitude(coordinates.get(0)); device.setLastLocationTime(at); + device.setLocationType(DeviceLocationType.DEVICE.getCode()); } - } else { + } else if (setNull) { device.setLongitude(null); device.setLatitude(null); device.setLastLocationTime(null); + device.setLocationType(null); } device.setLastTime(at); @@ -62,7 +63,7 @@ public class DeviceUtil { IotDeviceSysInfo sys = iot.getSys(); if (sys != null) { - setIotSysInfo(device, sys, iot.getAt()); + setIotSysInfo(device, sys, iot.getAt(), false); } device.setSoftwareVersion(iot.getVer()); } @@ -75,4 +76,16 @@ public class DeviceUtil { public static boolean isOrderUsing(DeviceVO device) { return device != null && device.getOrderDeviceId() != null && OrderDeviceStatus.inUse().contains(device.getOrderDeviceStatus()); } + + /** + * 判断经纬度是否有效 + * @param lon 经度 + * @param lat 纬度 + * @return 是否有效 + */ + public static boolean validLocation(BigDecimal lon, BigDecimal lat) { + return lon != null && lat != null + && !MathUtils.equals(lon, BigDecimal.ZERO) + && !MathUtils.equals(lat, BigDecimal.ZERO); + } } \ No newline at end of file diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/domain/LocationLog.java b/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/domain/LocationLog.java index b53b154..f22ef83 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/domain/LocationLog.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/domain/LocationLog.java @@ -84,4 +84,9 @@ public class LocationLog extends BaseEntity @Excel(name = "订单ID") @ApiModelProperty("订单ID") private Long orderId; + + @Excel(name = "类型") + @ApiModelProperty("类型(1设备定位 2手机定位)") + private String type; + } diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/mapper/LocationLogMapper.xml b/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/mapper/LocationLogMapper.xml index 34af8b6..dc18e3a 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/mapper/LocationLogMapper.xml +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/mapper/LocationLogMapper.xml @@ -23,7 +23,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" bll.quality, bll.iot_status, bll.device_id, - bll.order_id + bll.order_id, + bll.type @@ -48,6 +49,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and bll.order_id = #{query.orderId} and bll.at >= #{query.startTime} and bll.at <= #{query.endTime} + and bll.type = #{query.type} and bll.at >= #{query.timeRange[0]} and bll.at <= #{query.timeRange[1]} @@ -103,6 +105,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" iot_status, device_id, order_id, + type, #{mac}, @@ -120,6 +123,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{iotStatus}, #{deviceId}, #{orderId}, + #{type}, @@ -140,7 +144,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" quality, iot_status, device_id, - order_id + order_id, + type values @@ -175,6 +180,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" default, #{i.orderId}, default, + #{i.type}, + default, @@ -203,6 +210,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" iot_status = #{data.iotStatus}, device_id = #{data.deviceId}, order_id = #{data.orderId}, + type = #{data.type}, diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/service/LocationLogConverter.java b/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/service/LocationLogConverter.java index c65e9c7..34777b2 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/service/LocationLogConverter.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/service/LocationLogConverter.java @@ -2,7 +2,6 @@ package com.ruoyi.bst.locationLog.service; import com.ruoyi.bst.device.domain.DeviceVO; import com.ruoyi.bst.locationLog.domain.LocationLog; -import com.ruoyi.iot.domain.ReceiveMsg; public interface LocationLogConverter { diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/service/impl/LocationLogConverterImpl.java b/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/service/impl/LocationLogConverterImpl.java index b546a36..778bd26 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/service/impl/LocationLogConverterImpl.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/locationLog/service/impl/LocationLogConverterImpl.java @@ -1,35 +1,16 @@ package com.ruoyi.bst.locationLog.service.impl; -import com.ruoyi.bst.order.domain.enums.OrderStatus; -import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceStatus; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.bst.device.domain.DeviceVO; -import com.ruoyi.bst.device.service.DeviceIotService; -import com.ruoyi.bst.device.service.DeviceService; -import com.ruoyi.bst.device.utils.DeviceUtil; import com.ruoyi.bst.locationLog.domain.LocationLog; import com.ruoyi.bst.locationLog.service.LocationLogConverter; -import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceStatus; import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.iot.domain.IotDeviceSysInfo; -import com.ruoyi.iot.domain.ReceiveMsg; -import com.ruoyi.iot.service.IotConverter; -import com.ruoyi.iot.util.IotUtil; @Service public class LocationLogConverterImpl implements LocationLogConverter { - @Autowired - private DeviceService deviceService; - - @Autowired - private DeviceIotService deviceIotService; - - @Autowired - private IotConverter iotConverter; - @Override public LocationLog toPo(DeviceVO device) { if (device == null || StringUtils.isBlank(device.getMac())) { @@ -51,6 +32,7 @@ public class LocationLogConverterImpl implements LocationLogConverter { po.setLatitude(device.getLatitude()); po.setAt(device.getLastLocationTime()); po.setDeviceId(device.getId()); + po.setType(device.getLocationType()); if (OrderDeviceStatus.inUse().contains(device.getOrderDeviceStatus())) { po.setOrderId(device.getOrderId()); } diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderVO.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderVO.java index 90a2f82..fe9a6e6 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderVO.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/OrderVO.java @@ -22,6 +22,8 @@ public class OrderVO extends Order implements IotDevice { private String deviceSn; @ApiModelProperty("当前设备车牌号") private String deviceVehicleNum; + @ApiModelProperty("当前设备状态") + private String deviceStatus; @ApiModelProperty("当前设备所属用户ID") private Long deviceMchId; @ApiModelProperty("结束子区域ID") diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/dto/OrderOpenDeviceDTO.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/dto/OrderOpenDeviceDTO.java new file mode 100644 index 0000000..db0316a --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/dto/OrderOpenDeviceDTO.java @@ -0,0 +1,27 @@ +package com.ruoyi.bst.order.domain.dto; + +import java.math.BigDecimal; + +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 订单开锁请求参数 + */ +@Data +public class OrderOpenDeviceDTO { + @ApiModelProperty("订单id") + @NotNull(message = "订单id不能为空") + private Long orderId; + + @ApiModelProperty("手机定位经度") + private BigDecimal lon; + + @ApiModelProperty("手机定位纬度") + private BigDecimal lat; + + @ApiModelProperty("IOT是否必须成功") + private Boolean requiredIot; +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/query/OrderRankQuery.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/query/OrderRankQuery.java new file mode 100644 index 0000000..223d486 --- /dev/null +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/domain/query/OrderRankQuery.java @@ -0,0 +1,18 @@ +package com.ruoyi.bst.order.domain.query; + +import java.time.LocalDate; +import java.util.List; + +import org.springframework.format.annotation.DateTimeFormat; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class OrderRankQuery { + + @ApiModelProperty("日期范围") + @DateTimeFormat(pattern = "yyyy-MM-dd") + private List dateRange; + +} diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.xml b/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.xml index f336f00..0118146 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.xml +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/mapper/OrderMapper.xml @@ -83,7 +83,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" bod.return_lon, bod.return_lat, bd.longitude as current_lon, - bd.latitude as current_lat + bd.latitude as current_lat, + bd.status as device_status from diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderService.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderService.java index d06fd9f..82e3c3c 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderService.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/OrderService.java @@ -12,6 +12,7 @@ import com.ruoyi.bst.order.domain.dto.OrderChangeDeviceDTO; import com.ruoyi.bst.order.domain.dto.OrderCloseDeviceDTO; import com.ruoyi.bst.order.domain.dto.OrderCreateDTO; import com.ruoyi.bst.order.domain.dto.OrderEndDTO; +import com.ruoyi.bst.order.domain.dto.OrderOpenDeviceDTO; import com.ruoyi.bst.order.domain.dto.OrderRefundDTO; import com.ruoyi.bst.order.domain.dto.OrderVerifyDTO; import com.ruoyi.bst.order.domain.vo.OrderEndVO; @@ -158,7 +159,7 @@ public interface OrderService { * @param requiredIot 是否必须成功 * @return 结果 */ - public DeviceIotVO openDevice(OrderVO order, boolean requiredIot); + public DeviceIotVO openDevice(OrderOpenDeviceDTO dto); /** * 操作订单设备关闭 diff --git a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderServiceImpl.java b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderServiceImpl.java index 9b3a16a..45b452e 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderServiceImpl.java +++ b/ruoyi-service/src/main/java/com/ruoyi/bst/order/service/impl/OrderServiceImpl.java @@ -23,14 +23,17 @@ import com.ruoyi.bst.bonus.service.BonusConverter; import com.ruoyi.bst.bonus.service.BonusService; import com.ruoyi.bst.device.domain.Device; import com.ruoyi.bst.device.domain.DeviceVO; +import com.ruoyi.bst.device.domain.enums.DeviceLocationType; import com.ruoyi.bst.device.domain.enums.DeviceUnLockType; import com.ruoyi.bst.device.domain.vo.DeviceIotVO; import com.ruoyi.bst.device.service.DeviceIotService; import com.ruoyi.bst.device.service.DeviceService; -import com.ruoyi.bst.device.service.impl.DeviceValidatorImpl; +import com.ruoyi.bst.device.utils.DeviceUtil; import com.ruoyi.bst.fault.domain.Fault; import com.ruoyi.bst.fault.service.FaultConverter; import com.ruoyi.bst.fault.service.FaultService; +import com.ruoyi.bst.locationLog.domain.LocationLog; +import com.ruoyi.bst.locationLog.service.LocationLogConverter; import com.ruoyi.bst.locationLog.utils.LocationLogUtil; import com.ruoyi.bst.order.domain.Order; import com.ruoyi.bst.order.domain.OrderQuery; @@ -43,6 +46,7 @@ import com.ruoyi.bst.order.domain.dto.OrderChangeDeviceDTO; import com.ruoyi.bst.order.domain.dto.OrderCloseDeviceDTO; import com.ruoyi.bst.order.domain.dto.OrderCreateDTO; import com.ruoyi.bst.order.domain.dto.OrderEndDTO; +import com.ruoyi.bst.order.domain.dto.OrderOpenDeviceDTO; import com.ruoyi.bst.order.domain.dto.OrderRefundDTO; import com.ruoyi.bst.order.domain.dto.OrderVerifyDTO; import com.ruoyi.bst.order.domain.enums.OrderReturnType; @@ -59,7 +63,6 @@ import com.ruoyi.bst.orderDevice.domain.OrderDevice; import com.ruoyi.bst.orderDevice.domain.OrderDeviceVO; import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceReason; import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceStatus; -import com.ruoyi.bst.orderDevice.service.OrderDeviceConverter; import com.ruoyi.bst.orderDevice.service.OrderDeviceService; import com.ruoyi.bst.pay.domain.Pay; import com.ruoyi.bst.pay.domain.dto.PayRefundDTO; @@ -69,6 +72,8 @@ import com.ruoyi.bst.pay.service.PayConverter; import com.ruoyi.bst.pay.service.PayService; import com.ruoyi.bst.refund.domain.enums.RefundType; import com.ruoyi.bst.sms.service.SmsService; +import com.ruoyi.common.constant.CacheConstants; +import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisLock; import com.ruoyi.common.core.redis.enums.RedisLockKey; import com.ruoyi.common.utils.DateUtils; @@ -90,8 +95,6 @@ import lombok.extern.slf4j.Slf4j; @Service @Slf4j public class OrderServiceImpl implements OrderService { - - private final DeviceValidatorImpl deviceValidatorImpl; @Autowired private OrderMapper orderMapper; @@ -144,7 +147,7 @@ public class OrderServiceImpl implements OrderService { private FaultService faultService; @Autowired - private OrderDeviceConverter orderDeviceConverter; + private LocationLogConverter locationLogConverter; @Autowired private UserService userService; @@ -152,9 +155,8 @@ public class OrderServiceImpl implements OrderService { @Autowired private SmsService smsService; - OrderServiceImpl(DeviceValidatorImpl deviceValidatorImpl) { - this.deviceValidatorImpl = deviceValidatorImpl; - } + @Autowired + private RedisCache redisCache; /** * 查询订单 @@ -413,10 +415,8 @@ public class OrderServiceImpl implements OrderService { OrderDeviceVO orderDevice = bo.getOrderDevice(); DeviceVO device = bo.getDevice(); - // 处理其他线程操作 - scheduledExecutorService.execute(() -> { - this.handleDeviceLocation(device, dto); - }); + // 异步使用手机定位更新设备定位 + this.handleDeviceLocationAsync(device, dto.getLon(), dto.getLat()); // 设置订单数据 order.setEndTime(LocalDateTime.now()); // 结束时间 @@ -471,19 +471,35 @@ public class OrderServiceImpl implements OrderService { return vo; } - // 使用手机定位设置设备定位 - private void handleDeviceLocation(DeviceVO device, OrderEndDTO dto) { - if (dto.getLon() != null && dto.getLat() != null - && dto.getLon().compareTo(BigDecimal.ZERO) != 0 - && dto.getLat().compareTo(BigDecimal.ZERO) != 0) { - Device data = new Device(); - data.setId(device.getId()); - data.setLongitude(dto.getLon()); - data.setLatitude(dto.getLat()); - int rows = deviceService.updateDevice(data); - if (rows != 1) { - log.error("通过手机定位修改设备定位失败deviceId={}", device.getId()); - } + // 异步使用手机定位更新设备定位 + private void handleDeviceLocationAsync(DeviceVO device, BigDecimal lon, BigDecimal lat) { + if (device != null && device.getId() != null && DeviceUtil.validLocation(lon, lat)) { + scheduledExecutorService.execute(() -> { + device.setLongitude(lon); + device.setLatitude(lat); + device.setLocationType(DeviceLocationType.PHONE.getCode()); + + // 更新设备定位 + Device data = new Device(); + data.setId(device.getId()); + data.setLongitude(device.getLongitude()); + data.setLatitude(device.getLatitude()); + data.setLocationType(device.getLocationType()); + int rows = deviceService.updateDevice(data); + if (rows != 1) { + log.error("通过手机定位修改设备定位失败deviceId={}", device.getId()); + } + + // 转为定位日志 + LocationLog locationLog = locationLogConverter.toPo(device); + if (locationLog == null) { + log.error("转换定位日志失败: {}", device.getMac()); + return; + } + // 暂存到Redis缓存 + redisCache.rightPush(CacheConstants.LOCATION_LOG_QUEUE, locationLog); + + }); } } @@ -648,8 +664,11 @@ public class OrderServiceImpl implements OrderService { } @Override - public DeviceIotVO openDevice(OrderVO order, boolean requiredIot) { - ServiceUtil.assertion(order == null, "参数错误,order不允许为空"); + public DeviceIotVO openDevice(OrderOpenDeviceDTO dto) { + ServiceUtil.assertion(dto == null, "参数错误,dto不允许为空"); + + OrderVO order = this.selectOrderById(dto.getOrderId()); + ServiceUtil.assertion(order == null, "ID为%s的订单不存在", dto.getOrderId()); ServiceUtil.assertion(!OrderStatus.inUse().contains(order.getStatus()), "ID为%s的订单当前状态并非使用中,无法操作设备", order.getId()); @@ -658,8 +677,16 @@ public class OrderServiceImpl implements OrderService { ServiceUtil.assertion(!OrderDeviceStatus.inUse().contains(orderDevice.getStatus()), "ID为%s的订单设备当前状态并非使用中,无法操作设备", order.getId()); - return deviceIotService.unlock(orderDevice.getDeviceId(), DeviceUnLockType.USER, "订单开锁:" + order.getNo(), - requiredIot); + // 查询设备 + DeviceVO device = deviceService.selectDeviceById(orderDevice.getDeviceId()); + ServiceUtil.assertion(device == null, "ID为%s的设备不存在", orderDevice.getDeviceId()); + + // 异步使用手机定位更新设备定位 + this.handleDeviceLocationAsync(device, dto.getLon(), dto.getLat()); + + // 发送命令开锁 + return deviceIotService.unlock(device, DeviceUnLockType.USER, "订单开锁:" + order.getNo(), + dto.getRequiredIot()); } @Override @@ -688,6 +715,10 @@ public class OrderServiceImpl implements OrderService { ServiceUtil.assertion(inParkingVO.getInNoParking() != null && inParkingVO.getInNoParking(), "禁止在禁停区内停车"); } + // 异步使用手机定位更新设备定位 + this.handleDeviceLocationAsync(device, dto.getLon(), dto.getLat()); + + // 发送命令锁车 return deviceIotService.lock(device, false, "订单锁车:" + order.getNo(), dto.getRequiredIot()); } @@ -711,6 +742,10 @@ public class OrderServiceImpl implements OrderService { OrderDevice newOrderDevice = bo.getNewOrderDevice(); OrderVO order = bo.getOrder(); OrderInParkingVO inParkingVO = bo.getInParkingVO(); + DeviceVO oldDevice = bo.getOldDevice(); + + // 异步使用手机定位更新设备定位 + this.handleDeviceLocationAsync(oldDevice, dto.getLon(), dto.getLat()); // 操作数据库 Integer result = transactionTemplate.execute(status -> { diff --git a/ruoyi-service/src/main/java/com/ruoyi/iot/service/IotService.java b/ruoyi-service/src/main/java/com/ruoyi/iot/service/IotService.java index 64413d3..6fbb813 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/iot/service/IotService.java +++ b/ruoyi-service/src/main/java/com/ruoyi/iot/service/IotService.java @@ -106,4 +106,12 @@ public interface IotService { * @return 结果 */ CommandResponse setMusic(IotDevice device, String music, String reason); + + /** + * 上传数据 + * @param device 设备 + * @param reason 原因 + * @return 结果 + */ + CommandResponse uploadData(IotDevice device, String reason); } diff --git a/ruoyi-service/src/main/java/com/ruoyi/iot/service/impl/IotReceiveServiceImpl.java b/ruoyi-service/src/main/java/com/ruoyi/iot/service/impl/IotReceiveServiceImpl.java index f49362b..d00b934 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/iot/service/impl/IotReceiveServiceImpl.java +++ b/ruoyi-service/src/main/java/com/ruoyi/iot/service/impl/IotReceiveServiceImpl.java @@ -90,7 +90,7 @@ public class IotReceiveServiceImpl implements IotReceiveService { log.info("收到sys数据:{}", msg.getValue()); IotDeviceSysInfo sys = IotUtil.toSysInfo(msg.getValue()); LocalDateTime at = DateUtils.toLocalDateTime(msg.getAt()); - DeviceUtil.setIotSysInfo(device, sys, at); + DeviceUtil.setIotSysInfo(device, sys, at, true); // 更新设备信息 device.setOnlineStatus(DeviceOnlineStatus.ONLINE.getStatus()); diff --git a/ruoyi-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java b/ruoyi-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java index 2d38675..bbbbd43 100644 --- a/ruoyi-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java +++ b/ruoyi-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java @@ -319,7 +319,8 @@ public class IotServiceImpl implements IotService { commandLogService.addLog(po, loginUser); } - private CommandResponse uploadData(IotDevice device, String reason) { + @Override + public CommandResponse uploadData(IotDevice device, String reason) { return sendCommand(device, IotConstants.COMMAND_UPLOAD_DATA, reason); } diff --git a/ruoyi-web/src/main/java/com/ruoyi/web/app/AppDeviceIotController.java b/ruoyi-web/src/main/java/com/ruoyi/web/app/AppDeviceIotController.java index f01f8bd..13bc789 100644 --- a/ruoyi-web/src/main/java/com/ruoyi/web/app/AppDeviceIotController.java +++ b/ruoyi-web/src/main/java/com/ruoyi/web/app/AppDeviceIotController.java @@ -3,12 +3,15 @@ package com.ruoyi.web.app; import java.math.BigDecimal; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.ruoyi.bst.device.domain.DeviceVO; +import com.ruoyi.bst.device.domain.dto.DeviceBltUploadDTO; import com.ruoyi.bst.device.service.DeviceIotService; import com.ruoyi.bst.device.service.DeviceService; import com.ruoyi.common.annotation.Log; @@ -37,9 +40,9 @@ public class AppDeviceIotController extends BaseController { @ApiOperation("用户响铃寻车") @PutMapping("/ring") @Log(title = "用户响铃寻车", businessType = BusinessType.OTHER, bizIdName = "arg0", bizType = LogBizType.DEVICE) - public AjaxResult ring(@RequestParam(required = false) Long id, - @RequestParam(required = false) String sn, - @RequestParam(required = false) BigDecimal lon, + public AjaxResult ring(@RequestParam(required = false) Long id, + @RequestParam(required = false) String sn, + @RequestParam(required = false) BigDecimal lon, @RequestParam(required = false) BigDecimal lat) { DeviceVO device = null; if (id != null) { @@ -52,10 +55,17 @@ public class AppDeviceIotController extends BaseController { if (device.getAreaRequiredRingRadius() != null && device.getAreaRequiredRingRadius()) { ServiceUtil.assertion(lon == null || lat == null, "请开启定位后重试"); BigDecimal distance = GeoUtils.calculateDistance(device.getLatitude(), device.getLongitude(), lat, lon); - ServiceUtil.assertion(MathUtils.biggerThan(distance, device.getAreaRingRadius()), + ServiceUtil.assertion(MathUtils.biggerThan(distance, device.getAreaRingRadius()), "您当前距离车辆%s米,无法响铃寻车。请距离车辆%s米以内再试", distance, device.getAreaRingRadius()); } return toAjax(deviceIotService.play(device, IotConstants.PLAY_WARNING, "用户响铃寻车", true)); } + + @ApiOperation("蓝牙上传设备信息") + @PutMapping("/bltUpload") + @Log(title = "蓝牙上传设备信息", businessType = BusinessType.OTHER, bizType = LogBizType.DEVICE) + public AjaxResult bltUpload(@RequestBody @Validated DeviceBltUploadDTO dto) { + return toAjax(deviceIotService.bltUpload(dto)); + } } diff --git a/ruoyi-web/src/main/java/com/ruoyi/web/app/AppOrderController.java b/ruoyi-web/src/main/java/com/ruoyi/web/app/AppOrderController.java index 22e6076..51e2034 100644 --- a/ruoyi-web/src/main/java/com/ruoyi/web/app/AppOrderController.java +++ b/ruoyi-web/src/main/java/com/ruoyi/web/app/AppOrderController.java @@ -19,6 +19,7 @@ import com.ruoyi.bst.order.domain.dto.OrderChangeDeviceDTO; import com.ruoyi.bst.order.domain.dto.OrderCloseDeviceDTO; import com.ruoyi.bst.order.domain.dto.OrderCreateDTO; import com.ruoyi.bst.order.domain.dto.OrderEndDTO; +import com.ruoyi.bst.order.domain.dto.OrderOpenDeviceDTO; import com.ruoyi.bst.order.domain.enums.OrderReturnType; import com.ruoyi.bst.order.domain.enums.OrderStatus; import com.ruoyi.bst.order.domain.vo.OrderEndVO; @@ -98,9 +99,9 @@ public class AppOrderController extends BaseController { return success(orderService.createOrder(dto)); } - @ApiOperation("结束本人订单(还车)") + @ApiOperation("结束订单(还车)") @PutMapping("/end") - @Log(title = "结束本人订单(还车)", businessType = BusinessType.OTHER, bizIdName = "arg0", bizType = LogBizType.ORDER) + @Log(title = "结束订单(还车)", businessType = BusinessType.OTHER, bizIdName = "arg0", bizType = LogBizType.ORDER) public AjaxResult endOrder(@RequestBody @Validated OrderEndDTO dto) { OrderVO order = orderService.selectOrderById(dto.getOrderId()); ServiceUtil.assertion(!orderValidator.canEnd(order, getUserId()), "您无权结束ID为%s的订单", order.getId()); @@ -125,12 +126,13 @@ public class AppOrderController extends BaseController { @ApiOperation("订单开锁") @PutMapping("/openDevice") @Log(title = "订单开锁", businessType = BusinessType.OTHER, bizIdName = "arg0", bizType = LogBizType.ORDER) - public AjaxResult openDevice(Long orderId) { - OrderVO order = orderService.selectOrderById(orderId); + public AjaxResult openDevice(@Validated OrderOpenDeviceDTO dto) { + OrderVO order = orderService.selectOrderById(dto.getOrderId()); ServiceUtil.assertion(order == null, "订单不存在"); ServiceUtil.assertion(!orderValidator.canOpenDevice(order, getUserId()), "您无权操作ID为%s的订单设备开启", order.getId()); ServiceUtil.assertion(orderValidator.isTimeout(order), "当前订单已超时,请在安全的区域还车"); - return success(orderService.openDevice(order, true)); + dto.setRequiredIot(true); + return success(orderService.openDevice(dto)); } @ApiOperation("临时锁车") diff --git a/ruoyi-web/src/main/java/com/ruoyi/web/common/LoginController.java b/ruoyi-web/src/main/java/com/ruoyi/web/common/LoginController.java index 6a594ee..604ee05 100644 --- a/ruoyi-web/src/main/java/com/ruoyi/web/common/LoginController.java +++ b/ruoyi-web/src/main/java/com/ruoyi/web/common/LoginController.java @@ -2,9 +2,9 @@ package com.ruoyi.web.common; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.Set; -import com.ruoyi.common.utils.ServiceUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; @@ -20,6 +20,7 @@ import com.ruoyi.common.core.domain.model.LoginBody; import com.ruoyi.common.core.domain.model.WxLoginBody; import com.ruoyi.common.core.domain.vo.UserVO; import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.ServiceUtil; import com.ruoyi.dashboard.constants.StatKeys; import com.ruoyi.dashboard.domain.stat.StatQuery; import com.ruoyi.dashboard.domain.stat.StatVO; @@ -55,6 +56,9 @@ public class LoginController @Value("${ruoyi.loginById}") private Boolean loginById; + @Value("${ruoyi.loginByIdSecret}") + private String loginByIdSecret; + /** * 登录方法 * @@ -86,8 +90,9 @@ public class LoginController // ID登录(测试) @PostMapping("/loginById") @Anonymous - public AjaxResult loginById(Long userId) { + public AjaxResult loginById(Long userId, String secret) { ServiceUtil.assertion(!loginById, "接口不可用"); + ServiceUtil.assertion(!Objects.equals(loginByIdSecret, secret), "接口不可用"); AjaxResult ajax = AjaxResult.success(); // 生成令牌 String token = loginService.loginById(userId); diff --git a/ruoyi-web/src/main/resources/application-env.yml b/ruoyi-web/src/main/resources/application-env.yml index 14be2e7..75bb4c1 100644 --- a/ruoyi-web/src/main/resources/application-env.yml +++ b/ruoyi-web/src/main/resources/application-env.yml @@ -38,6 +38,8 @@ ruoyi: captchaType: math # 允许使用ID登录 loginById: true + # ID登录密钥 + loginByIdSecret: 123456 # 支付配置 pay: