手机辅助定位

This commit is contained in:
磷叶 2025-05-13 11:13:58 +08:00
parent c3f3b02a06
commit b9cfc3ef88
24 changed files with 282 additions and 75 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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"
<if test="query.orderUserPhone != null and query.orderUserPhone != ''">and suo.user_name like concat('%', #{query.orderUserPhone}, '%')</if>
<if test="query.lastTimeEnd != null">and bd.last_location_time &lt;= #{query.lastTimeEnd}</if>
<if test="query.lastTimeStart != null">and bd.last_location_time &gt;= #{query.lastTimeStart}</if>
<if test="query.locationType != null and query.locationType != ''">and bd.location_type = #{query.locationType}</if>
<if test="query.keyword != null and query.keyword != ''">
and (
bd.sn like concat('%', #{query.keyword}, '%')
@ -234,6 +236,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="lastOnlineTime != null">last_online_time,</if>
<if test="orderDeviceId != null">order_device_id,</if>
<if test="softwareVersion != null">software_version,</if>
<if test="locationType != null">location_type,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="modelId != null">#{modelId},</if>
@ -268,6 +271,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="lastOnlineTime != null">#{lastOnlineTime},</if>
<if test="orderDeviceId != null">#{orderDeviceId},</if>
<if test="softwareVersion != null">#{softwareVersion},</if>
<if test="locationType != null">#{locationType},</if>
</trim>
</insert>
@ -312,6 +316,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="data.lastOnlineTime != null">bd.last_online_time = #{data.lastOnlineTime},</if>
<if test="data.orderDeviceId != null">bd.order_device_id = #{data.orderDeviceId},</if>
<if test="data.softwareVersion != null">bd.software_version = #{data.softwareVersion},</if>
<if test="data.locationType != null">bd.location_type = #{data.locationType},</if>
</sql>
<delete id="deleteDeviceById" parameterType="Long">

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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<BigDecimal> 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);
}
}

View File

@ -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;
}

View File

@ -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
<include refid="searchTables"/>
</sql>
@ -48,6 +49,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="query.orderId != null "> and bll.order_id = #{query.orderId}</if>
<if test="query.startTime != null"> and bll.at &gt;= #{query.startTime}</if>
<if test="query.endTime != null"> and bll.at &lt;= #{query.endTime}</if>
<if test="query.type != null and query.type != ''"> and bll.type = #{query.type}</if>
<if test="query.timeRange != null and query.timeRange.size() > 1">
and bll.at &gt;= #{query.timeRange[0]}
and bll.at &lt;= #{query.timeRange[1]}
@ -103,6 +105,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="iotStatus != null">iot_status,</if>
<if test="deviceId != null">device_id,</if>
<if test="orderId != null">order_id,</if>
<if test="type != null">type,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="mac != null and mac != ''">#{mac},</if>
@ -120,6 +123,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="iotStatus != null">#{iotStatus},</if>
<if test="deviceId != null">#{deviceId},</if>
<if test="orderId != null">#{orderId},</if>
<if test="type != null">#{type},</if>
</trim>
</insert>
@ -140,7 +144,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
quality,
iot_status,
device_id,
order_id
order_id,
type
</trim>
values
<foreach collection="list" item="i" separator=",">
@ -175,6 +180,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="i.deviceId == null ">default,</if>
<if test="i.orderId != null ">#{i.orderId},</if>
<if test="i.orderId == null ">default,</if>
<if test="i.type != null ">#{i.type},</if>
<if test="i.type == null ">default,</if>
</trim>
</foreach>
</insert>
@ -203,6 +210,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="data.iotStatus != null">iot_status = #{data.iotStatus},</if>
<if test="data.deviceId != null">device_id = #{data.deviceId},</if>
<if test="data.orderId != null">order_id = #{data.orderId},</if>
<if test="data.type != null">type = #{data.type},</if>
</sql>
<delete id="deleteLocationLogByIds" parameterType="String">

View File

@ -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 {

View File

@ -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());
}

View File

@ -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")

View File

@ -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;
}

View File

@ -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<LocalDate> dateRange;
}

View File

@ -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 <include refid="searchTables"/>
</sql>

View File

@ -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);
/**
* 操作订单设备关闭

View File

@ -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 -> {

View File

@ -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);
}

View File

@ -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());

View File

@ -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);
}

View File

@ -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));
}
}

View File

@ -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("临时锁车")

View File

@ -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);

View File

@ -38,6 +38,8 @@ ruoyi:
captchaType: math
# 允许使用ID登录
loginById: true
# ID登录密钥
loginByIdSecret: 123456
# 支付配置
pay: