This commit is contained in:
磷叶 2025-05-16 17:33:46 +08:00
parent 66336eeed4
commit 33b469cdbc
17 changed files with 327 additions and 102 deletions

View File

@ -122,4 +122,9 @@ public class CacheConstants
* 操作日志队列 * 操作日志队列
*/ */
public static final String OPER_LOG_QUEUE = "oper_log_queue"; public static final String OPER_LOG_QUEUE = "oper_log_queue";
/**
* 设备更新物联网状态队列
*/
public static final String DEVICE_UPDATE_IOT_QUEUE = "device_update_iot_queue";
} }

View File

@ -140,7 +140,7 @@ public class MathUtils {
for (int i = 1; i < values.length; i++) { for (int i = 1; i < values.length; i++) {
BigDecimal value = values[i]; BigDecimal value = values[i];
if (value == null) { if (value == null) {
return null; continue;
} }
if (min == null || value.compareTo(min) < 0) { if (min == null || value.compareTo(min) < 0) {
min = value; min = value;

View File

@ -3,6 +3,7 @@ package com.ruoyi.bst.areaSub.service.impl;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import com.ruoyi.common.utils.ServiceUtil;
import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Geometry;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -106,15 +107,19 @@ public class AreaSubServiceImpl implements AreaSubService
@Override @Override
public int updateAreaSub(AreaSub areaSub) public int updateAreaSub(AreaSub areaSub)
{ {
AreaSubVO old = selectAreaSubById(areaSub.getId());
ServiceUtil.assertion(old == null, "ID为%s的待修改子区域不存在", areaSub.getId());
// 将边界值转Geometry对象 // 将边界值转Geometry对象
if (areaSub.getBoundaryStr() != null) { if (areaSub.getBoundaryStr() != null) {
Geometry geometry = GeoUtils.toGeometry(areaSub.getBoundaryStr()); Geometry geometry = GeoUtils.toGeometry(areaSub.getBoundaryStr());
areaSub.setBoundary(GeoUtils.wkt(geometry)); areaSub.setBoundary(GeoUtils.wkt(geometry));
} }
int result = areaSubMapper.updateAreaSub(areaSub); int result = areaSubMapper.updateAreaSub(areaSub);
if (result > 0) { if (result > 0) {
this.clearCache(areaSub.getAreaId()); this.clearCache(old.getAreaId());
} }
return result; return result;
@ -143,7 +148,7 @@ public class AreaSubServiceImpl implements AreaSubService
* @return 结果 * @return 结果
*/ */
@Override @Override
public int logicDel(List<Long> ids) { public int logicDel(List<Long> ids) {
if (CollectionUtils.isEmptyElement(ids)) { if (CollectionUtils.isEmptyElement(ids)) {
return 0; return 0;
} }
@ -155,16 +160,16 @@ public class AreaSubServiceImpl implements AreaSubService
// 删除数据库 // 删除数据库
int result = areaSubMapper.logicDel(ids); int result = areaSubMapper.logicDel(ids);
// 删除缓存 // 删除缓存
if (result > 0) { if (result > 0) {
for (AreaSubVO areaSub : list) { for (AreaSubVO areaSub : list) {
this.clearCache(areaSub.getAreaId()); this.clearCache(areaSub.getAreaId());
} }
} }
return result; return result;
} }
private List<AreaSubVO> selectAreaSubByIds(List<Long> ids) { private List<AreaSubVO> selectAreaSubByIds(List<Long> ids) {
if (CollectionUtils.isEmptyElement(ids)) { if (CollectionUtils.isEmptyElement(ids)) {

View File

@ -126,6 +126,10 @@ public class CommandLogServiceImpl implements CommandLogService
po.setType(CommandLogType.BLUETOOTH.getType()); po.setType(CommandLogType.BLUETOOTH.getType());
int rows = this.addLog(po, loginUser); int rows = this.addLog(po, loginUser);
if (rows > 0) { if (rows > 0) {
// TODO 记录定位日志
// 记录操作日志 // 记录操作日志
OperLog operLog = new OperLog(); OperLog operLog = new OperLog();
operLog.setTitle(po.getReason() + "(蓝牙)"); operLog.setTitle(po.getReason() + "(蓝牙)");

View File

@ -168,4 +168,11 @@ public interface DeviceMapper
*/ */
int updateByQuerySimple(@Param("data") Device data, @Param("query") DeviceQuery query); int updateByQuerySimple(@Param("data") Device data, @Param("query") DeviceQuery query);
/**
* 批量更新IOT数据
* @param list
* @return
*/
int batchUpdateIot(@Param("list") List<Device> list);
} }

View File

@ -498,4 +498,106 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</where> </where>
</update> </update>
<!-- batchUpdateIot -->
<update id="batchUpdateIot">
update bst_device
<trim prefix="SET" suffixOverrides=",">
<if test="list[0].voltage != null">
voltage = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.voltage}
</foreach>
else voltage end,
</if>
<if test="list[0].signalStrength != null">
signal_strength = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.signalStrength}
</foreach>
else signal_strength end,
</if>
<if test="list[0].quality != null">
quality = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.quality}
</foreach>
else quality end,
</if>
<if test="list[0].satellites != null">
satellites = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.satellites}
</foreach>
else satellites end,
</if>
<if test="list[0].iotStatus != null">
iot_status = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.iotStatus}
</foreach>
else iot_status end,
</if>
<if test="list[0].longitude != null">
longitude = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.longitude}
</foreach>
else longitude end,
</if>
<if test="list[0].latitude != null">
latitude = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.latitude}
</foreach>
else latitude end,
</if>
<if test="list[0].remainingPower != null">
remaining_power = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.remainingPower}
</foreach>
else remaining_power end,
</if>
<if test="list[0].lastTime != null">
last_time = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.lastTime}
</foreach>
else last_time end,
</if>
<if test="list[0].lastLocationTime != null">
last_location_time = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.lastLocationTime}
</foreach>
else last_location_time end,
</if>
<if test="list[0].onlineStatus != null">
online_status = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.onlineStatus}
</foreach>
else online_status end,
</if>
<if test="list[0].lastOnlineTime != null">
last_online_time = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.lastOnlineTime}
</foreach>
else last_online_time end,
</if>
<if test="list[0].softwareVersion != null">
software_version = case mac
<foreach collection="list" item="item">
when #{item.mac} then #{item.softwareVersion}
</foreach>
else software_version end,
</if>
</trim>
where mac in
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item.mac}
</foreach>
</update>
</mapper> </mapper>

View File

@ -231,4 +231,11 @@ public interface DeviceService
* @return * @return
*/ */
public int updateByQuerySimple(Device data, DeviceQuery query); public int updateByQuerySimple(Device data, DeviceQuery query);
/**
* 批量更新IOT数据
* @param list
* @return
*/
public int batchUpdateIot(List<Device> list);
} }

View File

@ -1,11 +1,9 @@
package com.ruoyi.bst.device.service.impl; package com.ruoyi.bst.device.service.impl;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -25,7 +23,6 @@ import com.ruoyi.bst.device.mapper.DeviceMapper;
import com.ruoyi.bst.device.service.DeviceIotService; import com.ruoyi.bst.device.service.DeviceIotService;
import com.ruoyi.bst.device.service.DeviceService; import com.ruoyi.bst.device.service.DeviceService;
import com.ruoyi.bst.device.utils.DeviceUtil; 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.locationLog.service.LocationLogConverter;
import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceStatus; import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceStatus;
import com.ruoyi.common.constant.CacheConstants; import com.ruoyi.common.constant.CacheConstants;
@ -33,6 +30,7 @@ import com.ruoyi.common.constants.ServiceCode;
import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.core.redis.RedisLock; import com.ruoyi.common.core.redis.RedisLock;
import com.ruoyi.common.core.redis.enums.RedisLockKey; import com.ruoyi.common.core.redis.enums.RedisLockKey;
import com.ruoyi.common.enums.LogBizType;
import com.ruoyi.common.utils.MathUtils; import com.ruoyi.common.utils.MathUtils;
import com.ruoyi.common.utils.ServiceUtil; import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
@ -44,6 +42,7 @@ import com.ruoyi.iot.enums.IotHttpStatus;
import com.ruoyi.iot.service.IotService; import com.ruoyi.iot.service.IotService;
import com.ruoyi.iot.service.impl.DeviceOnlineStatus; import com.ruoyi.iot.service.impl.DeviceOnlineStatus;
import com.ruoyi.iot.util.IotUtil; import com.ruoyi.iot.util.IotUtil;
import com.ruoyi.system.operLog.service.OperLogService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -75,6 +74,9 @@ public class DeviceIotServiceImpl implements DeviceIotService {
@Autowired @Autowired
private RedisCache redisCache; private RedisCache redisCache;
@Autowired
private OperLogService operLogService;
private final static Integer SUB_FAST = 5; // 上报频率 private final static Integer SUB_FAST = 5; // 上报频率
private final static Integer SUB_SLOW = 300; // 上报频率 private final static Integer SUB_SLOW = 300; // 上报频率
@ -117,7 +119,7 @@ public class DeviceIotServiceImpl implements DeviceIotService {
if (rows > 0) { if (rows > 0) {
// 发送命令开锁 // 发送命令开锁
CommandResponse res = iotService.unlock(device, SUB_FAST, reason); CommandResponse res = iotService.unlock(device, SUB_FAST, reason, 3);
boolean iot = IotUtil.isSuccess(res); boolean iot = IotUtil.isSuccess(res);
ServiceUtil.assertion(requiredIot && !iot, IotUtil.getMsg(res), ServiceCode.IOT_FAILED); ServiceUtil.assertion(requiredIot && !iot, IotUtil.getMsg(res), ServiceCode.IOT_FAILED);
vo.setIot(iot); vo.setIot(iot);
@ -126,11 +128,6 @@ public class DeviceIotServiceImpl implements DeviceIotService {
return rows; return rows;
}); });
// 异步执行3次设备监控
if (!requiredIot) {
this.asyncMonitorCount(device.getId(), 3);
}
return vo; return vo;
} }
@ -168,10 +165,10 @@ public class DeviceIotServiceImpl implements DeviceIotService {
CommandResponse res = null; CommandResponse res = null;
if (DeviceStatus.TEMP_LOCKED.getCode().equals(data.getStatus())) { if (DeviceStatus.TEMP_LOCKED.getCode().equals(data.getStatus())) {
// 临时锁车 // 临时锁车
res = iotService.tempLock(device, SUB_SLOW, reason); res = iotService.tempLock(device, SUB_SLOW, reason, 3);
} else { } else {
// 锁车 // 锁车
res = iotService.lock(device, SUB_SLOW, reason); res = iotService.lock(device, SUB_SLOW, reason, 3);
} }
boolean iot = IotUtil.isSuccess(res); boolean iot = IotUtil.isSuccess(res);
ServiceUtil.assertion(requiredIot && !iot, IotUtil.getMsg(res), ServiceCode.IOT_FAILED); ServiceUtil.assertion(requiredIot && !iot, IotUtil.getMsg(res), ServiceCode.IOT_FAILED);
@ -181,11 +178,6 @@ public class DeviceIotServiceImpl implements DeviceIotService {
return rows; return rows;
}); });
// 异步执行3次设备监控
if (!requiredIot) {
this.asyncMonitorCount(device.getId(), 3);
}
return vo; return vo;
} }
@ -214,7 +206,7 @@ public class DeviceIotServiceImpl implements DeviceIotService {
if (rows > 0) { if (rows > 0) {
// 发送命令锁车 // 发送命令锁车
CommandResponse res = iotService.qLock(device, SUB_FAST, reason); CommandResponse res = iotService.qLock(device, SUB_FAST, reason, 3);
boolean iot = IotUtil.isSuccess(res); boolean iot = IotUtil.isSuccess(res);
ServiceUtil.assertion(requiredIot && !iot, IotUtil.getMsg(res), ServiceCode.IOT_FAILED); ServiceUtil.assertion(requiredIot && !iot, IotUtil.getMsg(res), ServiceCode.IOT_FAILED);
vo.setIot(iot); vo.setIot(iot);
@ -223,11 +215,6 @@ public class DeviceIotServiceImpl implements DeviceIotService {
return rows; return rows;
}); });
// 异步执行3次设备监控
if (!requiredIot) {
this.asyncMonitorCount(device.getId(), 3);
}
return vo; return vo;
} }
@ -317,6 +304,7 @@ public class DeviceIotServiceImpl implements DeviceIotService {
return 0; return 0;
} }
Device data = new Device(); Device data = new Device();
data.setMac(device.getMac());
data.setVoltage(device.getVoltage()); data.setVoltage(device.getVoltage());
data.setSignalStrength(device.getSignalStrength()); data.setSignalStrength(device.getSignalStrength());
data.setQuality(device.getQuality()); data.setQuality(device.getQuality());
@ -330,10 +318,11 @@ public class DeviceIotServiceImpl implements DeviceIotService {
data.setOnlineStatus(device.getOnlineStatus()); data.setOnlineStatus(device.getOnlineStatus());
data.setLastOnlineTime(device.getLastOnlineTime()); data.setLastOnlineTime(device.getLastOnlineTime());
data.setSoftwareVersion(device.getSoftwareVersion()); data.setSoftwareVersion(device.getSoftwareVersion());
DeviceQuery query = new DeviceQuery();
query.setId(device.getId()); // 添加到缓存队列
query.setEqMac(device.getMac()); redisCache.rightPush(CacheConstants.DEVICE_UPDATE_IOT_QUEUE, data);
return deviceMapper.updateByQuerySimple(data, query);
return 1;
} }
@Override @Override
@ -388,10 +377,20 @@ public class DeviceIotServiceImpl implements DeviceIotService {
} }
// 判断电门与设备锁状态是否一致不一致则发送命令 // 判断电门与设备锁状态是否一致不一致则发送命令
if (DeviceLockStatus.OPEN.getCode().equals(device.getLockStatus()) && !DeviceQuality.OPEN.getCode().equals(device.getQuality())) { if (DeviceLockStatus.OPEN.getCode().equals(device.getLockStatus()) && !DeviceQuality.OPEN.getCode().equals(device.getQuality())) {
iotService.unlock(device, SUB_FAST, "【设备监控】电门异常未开启"); CommandResponse res = iotService.unlock(device, SUB_FAST, "重新尝试开锁", 1);
if (device.getOrderId() != null) {
operLogService.operSysLog("【设备监控】发现未开启的车辆", IotUtil.isSuccess(res), LogBizType.ORDER, device.getOrderId(), device);
} else {
operLogService.operSysLog("【设备监控】发现未开启的车辆", IotUtil.isSuccess(res), LogBizType.DEVICE, device.getId(), device);
}
} }
if (DeviceLockStatus.CLOSE.getCode().equals(device.getLockStatus()) && !DeviceQuality.CLOSE.getCode().equals(device.getQuality())) { if (DeviceLockStatus.CLOSE.getCode().equals(device.getLockStatus()) && !DeviceQuality.CLOSE.getCode().equals(device.getQuality())) {
iotService.lock(device, SUB_SLOW, "【设备监控】电门异常未关闭"); CommandResponse res = iotService.lock(device, SUB_SLOW, "重新尝试锁车", 1);
if (device.getOrderId() != null) {
operLogService.operSysLog("【设备监控】发现未关闭的车辆", IotUtil.isSuccess(res), LogBizType.ORDER, device.getOrderId(), device);
} else {
operLogService.operSysLog("【设备监控】发现未关闭的车辆", IotUtil.isSuccess(res), LogBizType.DEVICE, device.getId(), device);
}
} }
} }
@ -402,15 +401,6 @@ public class DeviceIotServiceImpl implements DeviceIotService {
this.monitor(device); this.monitor(device);
} }
private void asyncMonitorCount(Long deviceId, int count) {
scheduledExecutorService.schedule(() -> {
if (count > 0) {
this.monitor(Collections.singletonList(deviceId));
this.asyncMonitorCount(deviceId, count - 1);
}
}, 20 - count * 5, TimeUnit.SECONDS);
}
@Override @Override
public DeviceIotVO setMusic(DeviceVO device, String music, String reason, boolean requiredIot) { public DeviceIotVO setMusic(DeviceVO device, String music, String reason, boolean requiredIot) {
ServiceUtil.assertion(device == null, "设备不存在"); ServiceUtil.assertion(device == null, "设备不存在");
@ -467,14 +457,6 @@ public class DeviceIotServiceImpl implements DeviceIotService {
log.info("设备{}更新太频繁,跳过本次更新", device.getMac()); log.info("设备{}更新太频繁,跳过本次更新", device.getMac());
} }
// 创建定位日志
if (DeviceUtil.validLocation(device.getLongitude(), device.getLatitude())) {
LocationLog locationLog = locationLogConverter.toPo(device);
if (locationLog != null) {
redisCache.rightPush(CacheConstants.LOCATION_LOG_QUEUE, locationLog);
}
}
return 1; return 1;
} }
} }

View File

@ -1,9 +1,12 @@
package com.ruoyi.bst.device.service.impl; package com.ruoyi.bst.device.service.impl;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -24,6 +27,7 @@ import com.ruoyi.bst.device.service.DeviceValidator;
import com.ruoyi.bst.device.utils.DeviceUtil; import com.ruoyi.bst.device.utils.DeviceUtil;
import com.ruoyi.bst.model.service.ModelValidator; import com.ruoyi.bst.model.service.ModelValidator;
import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceStatus; import com.ruoyi.bst.orderDevice.domain.enums.OrderDeviceStatus;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.core.redis.RedisLock; import com.ruoyi.common.core.redis.RedisLock;
import com.ruoyi.common.core.redis.enums.RedisLockKey; import com.ruoyi.common.core.redis.enums.RedisLockKey;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
@ -62,6 +66,9 @@ public class DeviceServiceImpl implements DeviceService
@Autowired @Autowired
private DeviceValidator deviceValidator; private DeviceValidator deviceValidator;
@Autowired
private RedisCache redisCache;
/** /**
* 查询设备 * 查询设备
* *
@ -483,9 +490,8 @@ public class DeviceServiceImpl implements DeviceService
if (DeviceOnlineStatus.ONLINE.getStatus().equals(onlineStatus)) { if (DeviceOnlineStatus.ONLINE.getStatus().equals(onlineStatus)) {
data.setLastTime(LocalDateTime.now()); data.setLastTime(LocalDateTime.now());
} }
DeviceQuery query = new DeviceQuery(); data.setMac(mac);
query.setEqMac(mac); return deviceIotService.updateIot(data);
return deviceMapper.updateByQuerySimple(data, query);
} }
@Override @Override
@ -619,4 +625,59 @@ public class DeviceServiceImpl implements DeviceService
return deviceMapper.updateByQuerySimple(data, query); return deviceMapper.updateByQuerySimple(data, query);
} }
/**
* 批量更新设备IOT数据
*
* @param deviceList 设备列表
* @return 更新成功的记录数
*/
@Override
public int batchUpdateIot(List<Device> deviceList) {
if (CollectionUtils.isEmpty(deviceList)) {
return 0;
}
// 按相同字段分组提高更新效率
Map<String, List<Device>> groupMap = new HashMap<>();
for (Device device : deviceList) {
String key = getUpdateKey(device);
groupMap.computeIfAbsent(key, k -> new ArrayList<>()).add(device);
}
int total = 0;
// 分组批量更新
for (List<Device> group : groupMap.values()) {
// 分批处理每批500条
int batchSize = 500;
for (int i = 0; i < group.size(); i += batchSize) {
int endIndex = Math.min(i + batchSize, group.size());
List<Device> batch = group.subList(i, endIndex);
total += deviceMapper.batchUpdateIot(batch);
}
}
return total;
}
/**
* 获取设备更新字段的key
* 相同字段的设备会被分到同一组进行更新
*/
private String getUpdateKey(Device device) {
StringBuilder key = new StringBuilder();
key.append(device.getVoltage() != null ? "1" : "0")
.append(device.getSignalStrength() != null ? "1" : "0")
.append(device.getQuality() != null ? "1" : "0")
.append(device.getSatellites() != null ? "1" : "0")
.append(device.getIotStatus() != null ? "1" : "0")
.append(device.getLongitude() != null ? "1" : "0")
.append(device.getLatitude() != null ? "1" : "0")
.append(device.getRemainingPower() != null ? "1" : "0")
.append(device.getLastTime() != null ? "1" : "0")
.append(device.getLastLocationTime() != null ? "1" : "0")
.append(device.getOnlineStatus() != null ? "1" : "0")
.append(device.getLastOnlineTime() != null ? "1" : "0")
.append(device.getSoftwareVersion() != null ? "1" : "0");
return key.toString();
}
} }

View File

@ -33,7 +33,10 @@ public class OrderEndDTO implements LogBizParam {
@ApiModelProperty("是否必须IOT成功") @ApiModelProperty("是否必须IOT成功")
private Boolean requiredIot; private Boolean requiredIot;
@ApiModelProperty("是否需要调度费")
private Boolean needDispatchFee;
@Override @Override
public Object logBizId() { public Object logBizId() {
return orderId; return orderId;

View File

@ -432,7 +432,8 @@ public class OrderServiceImpl implements OrderService {
// 订单状态 // 订单状态
this.setOrderStatus(order, returnType); this.setOrderStatus(order, returnType);
// 订单费用 // 订单费用
this.setOrderFee(order, area, inParkingVO); boolean needDispatchFee = dto.getNeedDispatchFee() != null && dto.getNeedDispatchFee();
this.setOrderFee(order, area, inParkingVO, needDispatchFee);
Integer result = transactionTemplate.execute(status -> { Integer result = transactionTemplate.execute(status -> {
// 更新订单数据 // 更新订单数据
@ -547,8 +548,8 @@ public class OrderServiceImpl implements OrderService {
} }
// 设置订单费用 // 设置订单费用
private void setOrderFee(OrderVO order, AreaVO area, OrderInParkingVO inParkingVO) { private void setOrderFee(OrderVO order, AreaVO area, OrderInParkingVO inParkingVO, boolean needDispatchFee) {
OrderFeeVO orderFee = OrderUtil.calcOrderFee(order, area, inParkingVO, order.getEndTime()); OrderFeeVO orderFee = OrderUtil.calcOrderFee(order, area, inParkingVO, order.getEndTime(), needDispatchFee);
order.setManageFee(orderFee.getManageFee()); order.setManageFee(orderFee.getManageFee());
order.setDispatchFee(orderFee.getDispatchFee()); order.setDispatchFee(orderFee.getDispatchFee());
order.setRidingFee(orderFee.getRidingFee()); order.setRidingFee(orderFee.getRidingFee());
@ -677,7 +678,7 @@ public class OrderServiceImpl implements OrderService {
} }
// 计算金额 // 计算金额
return OrderUtil.calcOrderFee(order, area, inParkingVO, LocalDateTime.now()); return OrderUtil.calcOrderFee(order, area, inParkingVO, LocalDateTime.now(), true);
} }
@Override @Override

View File

@ -55,9 +55,10 @@ public class OrderUtil {
* @param area 运营区 * @param area 运营区
* @param inParkingVO 还车点 * @param inParkingVO 还车点
* @param endTime 结束时间 * @param endTime 结束时间
* @param needDispatchFee 是否需要调度费
* @return 结果 * @return 结果
*/ */
public static OrderFeeVO calcOrderFee(OrderVO order, AreaVO area, OrderInParkingVO inParkingVO, LocalDateTime endTime) { public static OrderFeeVO calcOrderFee(OrderVO order, AreaVO area, OrderInParkingVO inParkingVO, LocalDateTime endTime, boolean needDispatchFee) {
OrderFeeVO vo = new OrderFeeVO(); OrderFeeVO vo = new OrderFeeVO();
// 骑行费 // 骑行费
@ -80,22 +81,24 @@ public class OrderUtil {
} }
} }
// 若需要调度费则计算调度费
// 运营区外调度费 if (needDispatchFee) {
if (!inParkingVO.getInArea()) { // 运营区外调度费
BigDecimal manageFee = area.getVehicleManagementFee(); if (!inParkingVO.getInArea()) {
if (manageFee == null) { BigDecimal manageFee = area.getVehicleManagementFee();
manageFee = BigDecimal.ZERO; if (manageFee == null) {
manageFee = BigDecimal.ZERO;
}
vo.setManageFee(manageFee);
} }
vo.setManageFee(manageFee); // 停车点外调度费
} else if (!inParkingVO.getInParking()) {
// 停车点外调度费 BigDecimal dispatchFee = area.getDispatchFee();
else if (!inParkingVO.getInParking()) { if (dispatchFee == null) {
BigDecimal dispatchFee = area.getDispatchFee(); dispatchFee = BigDecimal.ZERO;
if (dispatchFee == null) { }
dispatchFee = BigDecimal.ZERO; vo.setDispatchFee(dispatchFee);
} }
vo.setDispatchFee(dispatchFee);
} }
// 总费用 // 总费用

View File

@ -39,30 +39,30 @@ public interface IotService {
/** /**
* 开锁 * 开锁
* @param device 设备 * @param device
* @param sub 上报频率 * @param sub
* @param reason 原因 * @param reason
* @return 结果 * @return
*/ */
CommandResponse unlock(IotDevice device, int sub, String reason); CommandResponse unlock(IotDevice device, int sub, String reason, int tryCount);
/** /**
* 锁车 * 锁车
* @param device 设备 * @param device
* @param sub 上报频率 * @param sub
* @param reason 原因 * @param reason
* @return 结果 * @return
*/ */
CommandResponse lock(IotDevice device, int sub, String reason); CommandResponse lock(IotDevice device, int sub, String reason, int tryCount);
/** /**
* 强制断电 * 强制断电
* @param device 设备 * @param device
* @param sub 上报频率 * @param sub
* @param reason 原因 * @param reason
* @return 结果 * @return
*/ */
CommandResponse qLock(IotDevice device, int sub, String reason); CommandResponse qLock(IotDevice device, int sub, String reason, int tryCount);
/** /**
* 播放语音 * 播放语音
@ -96,7 +96,15 @@ public interface IotService {
* @param reason * @param reason
* @return * @return
*/ */
CommandResponse tempLock(IotDevice device, int sub, String reason); CommandResponse tempLock(IotDevice device, int sub, String reason, int tryCount);
/**
* 临时锁车
* @param device
* @param sub
* @param reason
* @return
*/
/** /**
* 设置声音 * 设置声音

View File

@ -257,7 +257,23 @@ public class IotServiceImpl implements IotService {
} }
private CommandResponse sendCommand(IotDevice device, String command, String reason) { private CommandResponse sendCommand(IotDevice device, String command, String reason) {
return sendCommand(device, command, null, reason); return sendCommand(device, command, reason, 1);
}
private CommandResponse sendCommand(IotDevice device, String command, String reason, int tryCount) {
if (tryCount > 0) {
CommandResponse res = sendCommand(device, command, null, reason);
if (IotUtil.isSuccess(res) || tryCount <= 1) {
return res;
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
log.error("线程休眠异常", e);
}
return sendCommand(device, command, reason, tryCount - 1);
}
return null;
} }
// 发送MQTT命令 // 发送MQTT命令
@ -337,21 +353,21 @@ public class IotServiceImpl implements IotService {
} }
@Override @Override
public CommandResponse unlock(IotDevice device, int sub, String reason) { public CommandResponse unlock(IotDevice device, int sub, String reason, int tryCount) {
String command = IotConstants.COMMAND_UNLOCK + IotConstants.COMMAND_SUB + sub + IotConstants.COMMAND_SEPARATOR; String command = IotConstants.COMMAND_UNLOCK + IotConstants.COMMAND_SUB + sub + IotConstants.COMMAND_SEPARATOR;
return sendCommand(device, command, reason); return sendCommand(device, command, reason, tryCount);
} }
@Override @Override
public CommandResponse lock(IotDevice device, int sub, String reason) { public CommandResponse lock(IotDevice device, int sub, String reason, int tryCount) {
String command = IotConstants.COMMAND_LOCK + IotConstants.COMMAND_SUB + sub + IotConstants.COMMAND_SEPARATOR; String command = IotConstants.COMMAND_LOCK + IotConstants.COMMAND_SUB + sub + IotConstants.COMMAND_SEPARATOR;
return sendCommand(device, command, reason); return sendCommand(device, command, reason, tryCount);
} }
@Override @Override
public CommandResponse qLock(IotDevice device, int sub, String reason) { public CommandResponse qLock(IotDevice device, int sub, String reason, int tryCount) {
String command = IotConstants.COMMAND_QLOSE + IotConstants.COMMAND_SUB + sub + IotConstants.COMMAND_SEPARATOR; String command = IotConstants.COMMAND_QLOSE + IotConstants.COMMAND_SUB + sub + IotConstants.COMMAND_SEPARATOR;
return sendCommand(device, command, reason); return sendCommand(device, command, reason, tryCount);
} }
@Override @Override
@ -373,8 +389,8 @@ public class IotServiceImpl implements IotService {
} }
@Override @Override
public CommandResponse tempLock(IotDevice device, int sub, String reason) { public CommandResponse tempLock(IotDevice device, int sub, String reason, int tryCount) {
return sendCommand(device, IotConstants.COMMAND_LLOSE, reason); return sendCommand(device, IotConstants.COMMAND_LLOSE, reason, tryCount);
} }
@Override @Override

View File

@ -2,7 +2,9 @@ package com.ruoyi.task.device;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import com.ruoyi.common.utils.collection.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -10,6 +12,8 @@ import com.ruoyi.bst.device.domain.Device;
import com.ruoyi.bst.device.domain.DeviceQuery; import com.ruoyi.bst.device.domain.DeviceQuery;
import com.ruoyi.bst.device.service.DeviceIotService; import com.ruoyi.bst.device.service.DeviceIotService;
import com.ruoyi.bst.device.service.DeviceService; import com.ruoyi.bst.device.service.DeviceService;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.iot.service.impl.DeviceOnlineStatus; import com.ruoyi.iot.service.impl.DeviceOnlineStatus;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -24,6 +28,9 @@ public class DeviceTask {
@Autowired @Autowired
private DeviceService deviceService; private DeviceService deviceService;
@Autowired
private RedisCache redisCache;
// 监控所有设备 // 监控所有设备
public void monitorAll() { public void monitorAll() {
deviceIotService.monitor(new ArrayList<>()); deviceIotService.monitor(new ArrayList<>());
@ -36,12 +43,22 @@ public class DeviceTask {
// 条件在线且最后上报时间小于当前时间 - seconds秒 // 条件在线且最后上报时间小于当前时间 - seconds秒
DeviceQuery query = new DeviceQuery(); DeviceQuery query = new DeviceQuery();
query.setOnlineStatus(DeviceOnlineStatus.ONLINE.getStatus()); query.setOnlineStatus(DeviceOnlineStatus.ONLINE.getStatus());
query.setLastTimeEnd(LocalDateTime.now().plusSeconds(-seconds)); query.setLastTimeEnd(LocalDateTime.now().plusSeconds(-seconds));
Device data = new Device(); Device data = new Device();
data.setOnlineStatus(DeviceOnlineStatus.OFFLINE.getStatus()); data.setOnlineStatus(DeviceOnlineStatus.OFFLINE.getStatus());
int update = deviceService.updateByQuerySimple(data, query); int update = deviceService.updateByQuerySimple(data, query);
log.info("更新了{}条离线的设备数据", update); log.info("更新了{}条离线的设备数据", update);
} }
public void refreshIot() {
// 从队列中获取数据
List<Device> deviceList = redisCache.getAndClearCacheList(CacheConstants.DEVICE_UPDATE_IOT_QUEUE);
if (CollectionUtils.isEmptyElement(deviceList)) {
return ;
}
int rows = deviceService.batchUpdateIot(deviceList);
log.info("更新了{}条设备IOT数据", rows);
}
} }

View File

@ -113,6 +113,7 @@ public class AppOrderController extends BaseController {
dto.setReturnType(OrderReturnType.NORMAL.getCode()); dto.setReturnType(OrderReturnType.NORMAL.getCode());
dto.setEndReason("用户【" + getNickName() + "】手动还车"); dto.setEndReason("用户【" + getNickName() + "】手动还车");
dto.setRequiredIot(false); dto.setRequiredIot(false);
dto.setNeedDispatchFee(true);
OrderEndVO vo = orderService.endOrder(dto); OrderEndVO vo = orderService.endOrder(dto);
if (vo.getDb() > 0) { if (vo.getDb() > 0) {
return success(vo); return success(vo);

View File

@ -115,6 +115,9 @@ public class OrderController extends BaseController
dto.setReturnType(OrderReturnType.AUXILIARY.getCode()); dto.setReturnType(OrderReturnType.AUXILIARY.getCode());
dto.setEndReason("管理员【" + getNickName() + "】手动还车"); dto.setEndReason("管理员【" + getNickName() + "】手动还车");
dto.setRequiredIot(false); dto.setRequiredIot(false);
if (dto.getNeedDispatchFee() == null) {
dto.setNeedDispatchFee(false);
}
OrderEndVO vo = orderService.endOrder(dto); OrderEndVO vo = orderService.endOrder(dto);
if (vo.getDb() > 0) { if (vo.getDb() > 0) {
return success(vo); return success(vo);