debug支付、套餐

This commit is contained in:
磷叶 2025-06-07 14:45:59 +08:00
parent 6282f33cc3
commit ba39caca4d
18 changed files with 176 additions and 106 deletions

View File

@ -9,5 +9,8 @@ public class CommandLogQuery extends CommandLogVO{
@ApiModelProperty("精准MAC")
private String eqMac;
@ApiModelProperty("排除命令")
private String excludeCommand;
}

View File

@ -37,6 +37,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="query.userName != null and query.userName != ''"> and bcl.user_name like concat('%', #{query.userName}, '%')</if>
<if test="query.iotCode != null "> and bcl.iot_code = #{query.iotCode}</if>
<if test="query.orderId != null "> and bcl.order_id = #{query.orderId}</if>
<if test="query.excludeCommand != null and query.excludeCommand != ''"> and bcl.command != #{query.excludeCommand}</if>
${query.params.dataScope}
</sql>

View File

@ -1,6 +1,7 @@
package com.ruoyi.bst.credit.domain;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import com.ruoyi.common.core.validate.ValidGroup;
@ -13,6 +14,7 @@ public class CreditVO extends Credit {
// 管理员
@ApiModelProperty("管理员手机号")
@NotBlank(message = "管理员手机号不能为空", groups = {ValidGroup.Create.class})
@Size(max = 11, message = "管理员手机号不允许超过11个字符")
private String adminMobile;
@ApiModelProperty("管理员名称")
private String adminName;

View File

@ -72,4 +72,18 @@ public class DeviceCacheKey {
*/
public static final String LAST_ONLINE_TIME = "lastOnlineTime";
/**
* 手机经度
*/
public static final String MOBILE_LON = "mobileLon";
/**
* 手机纬度
*/
public static final String MOBILE_LAT = "mobileLat";
/**
* 手机最后定位时间
*/
public static final String MOBILE_LOCATION_TIME = "mobileLocationTime";
}

View File

@ -155,6 +155,19 @@ public class Device extends BaseEntity implements IotDevice, LogBizParam
@ApiModelProperty("定位类型1设备定位 2手机定位")
private String locationType;
@Excel(name = "手机经度")
@ApiModelProperty("手机经度")
private BigDecimal mobileLon;
@Excel(name = "手机纬度")
@ApiModelProperty("手机纬度")
private BigDecimal mobileLat;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Excel(name = "手机最后定位时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("手机最后定位时间")
private LocalDateTime mobileLocationTime;
@Override
public String mac() {
return this.mac;

View File

@ -44,6 +44,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
bd.order_device_id,
bd.software_version,
bd.location_type,
bd.mobile_lon,
bd.mobile_lat,
bd.mobile_location_time,
mch.nick_name as mch_name,
mch.point as mch_point,
bm.name as model_name,
@ -241,6 +244,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="orderDeviceId != null">order_device_id,</if>
<if test="softwareVersion != null">software_version,</if>
<if test="locationType != null">location_type,</if>
<if test="mobileLon != null">mobile_lon,</if>
<if test="mobileLat != null">mobile_lat,</if>
<if test="mobileLocationTime != null">mobile_location_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="modelId != null">#{modelId},</if>
@ -275,6 +281,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="orderDeviceId != null">#{orderDeviceId},</if>
<if test="softwareVersion != null">#{softwareVersion},</if>
<if test="locationType != null">#{locationType},</if>
<if test="mobileLon != null">#{mobileLon},</if>
<if test="mobileLat != null">#{mobileLat},</if>
<if test="mobileLocationTime != null">#{mobileLocationTime},</if>
</trim>
</insert>
@ -319,6 +328,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<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>
<if test="data.mobileLon != null">bd.mobile_lon = #{data.mobileLon},</if>
<if test="data.mobileLat != null">bd.mobile_lat = #{data.mobileLat},</if>
<if test="data.mobileLocationTime != null">bd.mobile_location_time = #{data.mobileLocationTime},</if>
</sql>
<delete id="deleteDeviceById" parameterType="Long">

View File

@ -93,15 +93,22 @@ public class DeviceConverterImpl implements DeviceConverter{
if (device.getSoftwareVersion() != null) {
info.put(DeviceCacheKey.SOFTWARE_VERSION, device.getSoftwareVersion());
}
if (device.getLocationType() != null) {
info.put(DeviceCacheKey.LOCATION_TYPE, device.getLocationType());
}
if (device.getOnlineStatus() != null) {
info.put(DeviceCacheKey.ONLINE_STATUS, device.getOnlineStatus());
}
if (device.getLastOnlineTime() != null) {
info.put(DeviceCacheKey.LAST_ONLINE_TIME, DateUtils.format(device.getLastOnlineTime(), DateUtils.YYYY_MM_DD_HH_MM_SS));
}
if (device.getMobileLon() != null) {
info.put(DeviceCacheKey.MOBILE_LON, device.getMobileLon());
}
if (device.getMobileLat() != null) {
info.put(DeviceCacheKey.MOBILE_LAT, device.getMobileLat());
}
if (device.getMobileLocationTime() != null) {
info.put(DeviceCacheKey.MOBILE_LOCATION_TIME, DateUtils.format(device.getMobileLocationTime(), DateUtils.YYYY_MM_DD_HH_MM_SS));
}
return info;
}

View File

@ -433,7 +433,7 @@ public class DeviceIotServiceImpl implements DeviceIotService {
ServiceUtil.assertion(device == null, "设备不存在");
// 更新设备信息
DeviceUtil.setIotSysInfo(device, dto.getSys(), LocalDateTime.now(), true, DeviceLocationType.PHONE);
DeviceUtil.setIotSysInfo(device, dto.getSys(), LocalDateTime.now(), DeviceLocationType.PHONE);
this.updateIot(device);

View File

@ -2,7 +2,6 @@ package com.ruoyi.bst.device.utils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -20,48 +19,36 @@ import com.ruoyi.iot.service.impl.DeviceOnlineStatus;
public class DeviceUtil {
public static void setIotSysInfo(DeviceVO device, IotDeviceSysInfo sys, LocalDateTime at, boolean setNull) {
setIotSysInfo(device, sys, at, setNull, DeviceLocationType.DEVICE);
}
/**
* 设置设备系统信息
*
* @param device 设备
* @param sys 设备信息
* @param at 时间
* @param setNull 若定位不正常是否设置为空
* @param convertLocation 是否转换经纬度坐标系
* @param locationType 定位类型
*/
public static void setIotSysInfo(DeviceVO device, IotDeviceSysInfo sys, LocalDateTime at, boolean setNull,
DeviceLocationType locationType) {
public static void setIotSysInfo(DeviceVO device, IotDeviceSysInfo sys, LocalDateTime at, DeviceLocationType locationType) {
if (device == null || sys == null) {
return;
}
// 转换经纬度坐标系并赋值
// 只有定位是正常的 && 卫星信号不弱 才认为是有获取到定位
if (DeviceUtil.validLocation(sys.getLon(), sys.getLat()) && !DeviceUtil.isLowSatelliteSignal(sys.getS())) {
List<BigDecimal> coordinates = null;
// 转换坐标
if (locationType == DeviceLocationType.DEVICE) {
coordinates = GpsCoordinateUtils.coordinateConvert(sys.getLon(), sys.getLat());
} else if (locationType == DeviceLocationType.PHONE) {
coordinates = Arrays.asList(sys.getLon(), sys.getLat());
}
if (locationType == DeviceLocationType.DEVICE && DeviceUtil.validLocation(sys.getLon(), sys.getLat()) && !DeviceUtil.isLowSatelliteSignal(sys.getS())) {
// 转换经纬度坐标系并赋值
List<BigDecimal> coordinates = GpsCoordinateUtils.coordinateConvert(sys.getLon(), sys.getLat());
if (coordinates != null && coordinates.size() >= 2) {
device.setLongitude(coordinates.get(0));
device.setLatitude(coordinates.get(1));
device.setLastLocationTime(at);
device.setLocationType(locationType.getCode());
}
} else if (setNull) {
device.setLongitude(null);
device.setLatitude(null);
device.setLastLocationTime(null);
device.setLocationType(null);
}
// 手机定位
if (locationType == DeviceLocationType.PHONE && DeviceUtil.validMobileLocation(sys.getLon(), sys.getLat())) {
device.setMobileLon(sys.getLon());
device.setMobileLat(sys.getLat());
device.setMobileLocationTime(at);
}
device.setLastTime(at);
@ -85,7 +72,7 @@ public class DeviceUtil {
IotDeviceSysInfo sys = iot.getSys();
if (sys != null) {
setIotSysInfo(device, sys, iot.getAt(), false);
setIotSysInfo(device, sys, iot.getAt(), DeviceLocationType.DEVICE);
}
device.setSoftwareVersion(iot.getVer());
}
@ -132,8 +119,16 @@ public class DeviceUtil {
if (info.containsKey(DeviceCacheKey.SOFTWARE_VERSION)) {
device.setSoftwareVersion(String.valueOf(info.get(DeviceCacheKey.SOFTWARE_VERSION)));
}
if (info.containsKey(DeviceCacheKey.LOCATION_TYPE)) {
device.setLocationType(String.valueOf(info.get(DeviceCacheKey.LOCATION_TYPE)));
// 手机定位
if (info.containsKey(DeviceCacheKey.MOBILE_LON)) {
device.setMobileLon(JsonUtils.getBigDecimal(info.get(DeviceCacheKey.MOBILE_LON)));
}
if (info.containsKey(DeviceCacheKey.MOBILE_LAT)) {
device.setMobileLat(JsonUtils.getBigDecimal(info.get(DeviceCacheKey.MOBILE_LAT)));
}
if (info.containsKey(DeviceCacheKey.MOBILE_LOCATION_TIME)) {
device.setMobileLocationTime(JsonUtils.getLocalDatetime(info.get(DeviceCacheKey.MOBILE_LOCATION_TIME)));
}
// 在线状态
@ -198,21 +193,6 @@ public class DeviceUtil {
return s == null || s <= 5;
}
/**
* 根据推送设置设备信息
*
* @param device 设备
* @param sys sys信息
* @param at 时间
* @param setNull 是否设置为空
*/
public static void setIotSysInfoByReceive(DeviceVO device, IotDeviceSysInfo sys, LocalDateTime at, boolean setNull) {
setIotSysInfo(device, sys, at, setNull);
device.setOnlineStatus(DeviceOnlineStatus.ONLINE.getStatus());
device.setLastOnlineTime(at);
}
/**
* 判断设备是否离线
*
@ -222,4 +202,18 @@ public class DeviceUtil {
public static boolean isOffline(DeviceVO device) {
return device != null && device.getOnlineStatus() != null && DeviceOnlineStatus.OFFLINE.getStatus().equals(device.getOnlineStatus());
}
/**
* 判断手机定位是否有效
* 手机定位经纬度不能为0
* 需要大于6位小数
* @param lon
* @param lat
* @return
*/
public static boolean validMobileLocation(BigDecimal lon, BigDecimal lat) {
return lon != null && lat != null
&& !MathUtils.equals(lon, BigDecimal.ZERO) && !MathUtils.equals(lat, BigDecimal.ZERO)
&& lon.scale() >= 6 && lat.scale() >= 6;
}
}

View File

@ -3,6 +3,7 @@ package com.ruoyi.bst.order.domain.dto;
import javax.validation.constraints.NotNull;
import com.ruoyi.bst.order.domain.vo.OrderCalcRideFeeVO;
import com.ruoyi.common.core.interfaces.LogBizParam;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -11,7 +12,7 @@ import lombok.Data;
* 押金抵扣DTO
*/
@Data
public class OrderDeductDTO {
public class OrderDeductDTO implements LogBizParam {
@ApiModelProperty("订单ID")
@NotNull(message = "订单ID不能为空")
@ -26,4 +27,9 @@ public class OrderDeductDTO {
@ApiModelProperty("费用")
@NotNull(message = "费用不能为空")
private OrderCalcRideFeeVO fee;
@Override
public Object logBizId() {
return id;
}
}

View File

@ -546,40 +546,33 @@ public class OrderServiceImpl implements OrderService {
// 异步使用手机定位更新设备定位
private void handleDeviceLocationAsync(DeviceVO device, BigDecimal lon, BigDecimal lat) {
if (device != null && device.getId() != null && StringUtils.isNotBlank(device.getMac()) && DeviceUtil.validLocation(lon, lat)) {
scheduledExecutorService.execute(() -> {
if (device != null && device.getId() != null && StringUtils.isNotBlank(device.getMac()) && DeviceUtil.validMobileLocation(lon, lat)) {
// 更新设备手机定位
Device data = new Device();
data.setMac(device.getMac());
data.setMobileLon(lon);
data.setMobileLat(lat);
data.setMobileLocationTime(LocalDateTime.now());
int rows = deviceIotService.updateIot(data);
if (rows != 1) {
log.error("通过手机定位修改设备定位失败deviceMac={}", device.getMac());
}
// 若卫星信号弱或者离线则更新设备定位
if (DeviceUtil.isLowSatelliteSignal(device) || DeviceUtil.isOffline(device)) {
Device data = new Device();
data.setMac(device.getMac());
data.setLongitude(lon);
data.setLatitude(lat);
data.setLocationType(DeviceLocationType.PHONE.getCode());
data.setLastLocationTime(LocalDateTime.now());
int rows = deviceIotService.updateIot(data);
if (rows != 1) {
log.error("通过手机定位修改设备定位失败deviceMac={}", device.getMac());
}
}
// 直接保存手机定位日志
DeviceVO vo = new DeviceVO();
BeanUtils.copyProperties(device, vo);
vo.setLongitude(lon);
vo.setLatitude(lat);
vo.setLocationType(DeviceLocationType.PHONE.getCode());
vo.setLastLocationTime(LocalDateTime.now());
LocationLog locationLog = locationLogConverter.toPo(vo);
if (locationLog == null) {
log.error("通过手机定位转换定位日志失败: {}", device.getMac());
return;
}
// 直接保存手机定位日志
DeviceVO vo = new DeviceVO();
BeanUtils.copyProperties(device, vo);
vo.setLongitude(lon);
vo.setLatitude(lat);
vo.setLocationType(DeviceLocationType.PHONE.getCode());
vo.setLastLocationTime(LocalDateTime.now());
LocationLog locationLog = locationLogConverter.toPo(vo);
if (locationLog == null) {
log.error("通过手机定位转换定位日志失败: {}", device.getMac());
return;
}
// 暂存到Redis缓存
redisCache.rightPush(CacheConstants.LOCATION_LOG_QUEUE, locationLog);
});
// 暂存到Redis缓存
redisCache.rightPush(CacheConstants.LOCATION_LOG_QUEUE, locationLog);
}
}

View File

@ -226,7 +226,7 @@ public class OrderDeviceServiceImpl implements OrderDeviceService
}
data.setReturnLon(inParkingVO.getActualLon());
data.setReturnLat(inParkingVO.getActualLat());
if (inParkingVO.getDeviceInArea() != null) {
if (inParkingVO.getDeviceAreaSub() != null) {
data.setReturnMode(OrderReturnMode.DEVICE.getCode());
} else {
data.setReturnMode(OrderReturnMode.MOBILE.getCode());

View File

@ -290,9 +290,11 @@ public class PayServiceImpl implements PayService {
PayQuery updateQuery = new PayQuery();
updateQuery.setStatus(pay.getStatus());
updateQuery.setId(pay.getId());
updateQuery.setAmount(pay.getAmount());
int update = payMapper.updateByQuery(closeData, updateQuery);
if (update == 1) {
// 调用支付API关闭订单若支付金额为0则不调用
if (update == 1 && !MathUtils.equals(pay.getAmount(), BigDecimal.ZERO)) {
// 关闭支付中的订单
if (PayStatus.PAYING.getStatus().equals(pay.getStatus())) {
// 查询渠道信息
@ -382,10 +384,8 @@ public class PayServiceImpl implements PayService {
this.refreshPayResultBeforeExpire(pay.getNo());
}, 10, TimeUnit.SECONDS);
} else {
// 异步处理支付成功
scheduledExecutorService.schedule(() -> {
this.handleSuccess(pay.getNo(), LocalDateTime.now());
}, 10, TimeUnit.SECONDS);
// 处理支付成功
this.handleSuccess(pay.getNo(), LocalDateTime.now());
}
return vo;
@ -405,16 +405,8 @@ public class PayServiceImpl implements PayService {
return;
}
// 若支付单已过期且未支付成功则关闭订单
Duration duration = Duration.between(LocalDateTime.now(), pay.getExpireTime());
long seconds = duration.getSeconds();
if (seconds <= 0 && !PayStatus.payedList().contains(pay.getStatus())) {
this.close(pay);
return;
}
// 未支付成功并且还未过期则继续延迟刷新
if (PayStatus.PAYING.getStatus().equals(pay.getStatus()) && seconds > 0) {
// 未支付成功继续延迟刷新
if (PayStatus.PAYING.getStatus().equals(pay.getStatus())) {
log.debug("{}未支付成功,继续延迟刷新", pay.getId());
scheduledExecutorService.schedule(() -> {
this.refreshPayResultBeforeExpire(no);
@ -456,9 +448,20 @@ public class PayServiceImpl implements PayService {
// 获取支付结果若成功则处理支付成功
Object result = this.queryPayInfo(payApi, pay, channel, app);
boolean isPaySuccess = payApi.isPaySuccess(result);
// 支付成功处理支付成功
if (isPaySuccess) {
this.handleSuccess(pay, payApi.getPayTime(result));
}
// 未支付成功判断是否过期若过期则关闭订单
else if (pay.getExpireTime() != null) {
Duration duration = Duration.between(LocalDateTime.now(), pay.getExpireTime());
long seconds = duration.getSeconds();
if (seconds <= 0 && !PayStatus.payedList().contains(pay.getStatus())) {
this.close(pay);
return;
}
}
}
/**

View File

@ -94,7 +94,7 @@ public class SuitServiceImpl implements SuitService
Integer result = transactionTemplate.execute(status -> {
int rows = suitMapper.insertSuit(suit);
if (rows > 0) {
// 更新套餐关联
this.updateSuitModel(suit);
@ -104,7 +104,7 @@ public class SuitServiceImpl implements SuitService
suitValidator.validate(vo);
// 计算并更新可用时长
this.updateSuitSeconds(vo);
// this.updateSuitSeconds(vo);
}
return rows;
@ -143,7 +143,7 @@ public class SuitServiceImpl implements SuitService
suitValidator.validate(vo);
// 计算并更新可用时长
this.updateSuitSeconds(vo);
// this.updateSuitSeconds(vo);
}
return rows;

View File

@ -73,8 +73,8 @@ public class SuitValidatorImpl implements SuitValidator {
ServiceUtil.assertion(startRule.getStartingPrice() == null, "起步价不能为空");
ServiceUtil.assertion(startRule.getTimeoutTime() == null, "超时时长不能为空");
ServiceUtil.assertion(startRule.getTimeoutPrice() == null, "超时价格不能为空");
ServiceUtil.assertion(startRule.getStartingPrice().compareTo(BigDecimal.ZERO) <= 0, "起步价不能小于或等于0");
ServiceUtil.assertion(startRule.getTimeoutPrice().compareTo(BigDecimal.ZERO) <= 0, "超时价格不能小于或等于0");
ServiceUtil.assertion(startRule.getStartingPrice().compareTo(BigDecimal.ZERO) < 0, "起步价不能小于0");
ServiceUtil.assertion(startRule.getTimeoutPrice().compareTo(BigDecimal.ZERO) < 0, "超时价格不能小于0");
ServiceUtil.assertion(startRule.getStartingTime() <= 0, "起步时长不能小于或等于0");
ServiceUtil.assertion(startRule.getTimeoutTime() <= 0, "超时时长不能小于或等于0");
} else if (SuitRidingRule.INTERVAL_FEE.getCode().equals(suit.getRidingRule())) {

View File

@ -17,6 +17,7 @@ import com.ruoyi.bst.areaSub.domain.AreaSubVO;
import com.ruoyi.bst.areaSub.service.AreaSubService;
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.DeviceLockStatus;
import com.ruoyi.bst.device.domain.enums.DeviceQuality;
import com.ruoyi.bst.device.domain.enums.DeviceStatus;
@ -99,14 +100,13 @@ public class IotReceiveServiceImpl implements IotReceiveService {
return;
}
deviceAssembler.assembleIot(device);
BigDecimal oldLon = device.getLongitude();
BigDecimal oldLat = device.getLatitude();
LocalDateTime lastLocationTime = device.getLastLocationTime();
// 转为设备信息
IotDeviceSysInfo sys = IotUtil.toSysInfo(msg.getValue());
LocalDateTime at = DateUtils.toLocalDateTime(msg.getAt());
DeviceUtil.setIotSysInfoByReceive(device, sys, at, true);
DeviceUtil.setIotSysInfo(device, sys, at, DeviceLocationType.DEVICE);
device.setOnlineStatus(DeviceOnlineStatus.ONLINE.getStatus());
device.setLastOnlineTime(at);
// 更新设备信息
deviceIotService.updateIot(device);

View File

@ -29,6 +29,9 @@ public class PayTask implements ApplicationRunner {
@Autowired
private ScheduledExecutorService scheduledExecutorService;
/**
* 启动时刷新支付结果
*/
@Override
public void run(ApplicationArguments args) throws Exception {
// 查询所有未支付的支付单
@ -47,5 +50,24 @@ public class PayTask implements ApplicationRunner {
}, 0, TimeUnit.SECONDS);
}
}
/**
* 定时刷新支付结果
*/
public void refreshPayResult() {
// 查询所有未支付的支付单
PayQuery query = new PayQuery();
query.setStatusList(PayStatus.unPayList());
List<String> payList = payMapper.selectNoList(query);
log.info("查询到{}条未支付的支付单", payList.size());
for (String no : payList) {
try {
payService.refreshPayResult(no);
} catch (Exception e) {
log.error("刷新支付结果失败,支付单号:{}", no, e);
}
}
}
}

View File

@ -158,7 +158,7 @@ public class OrderController extends BaseController
/**
* 押金抵扣
*/
@Log(title = "押金抵扣", businessType = BusinessType.UPDATE, bizIdName = "arg0", bizType = LogBizType.ORDER)
@Log(title = "管理员押金抵扣", businessType = BusinessType.UPDATE, bizIdName = "arg0", bizType = LogBizType.ORDER)
@PreAuthorize("@ss.hasPermi('bst:order:deduct')")
@PutMapping("/deduct")
public AjaxResult deduct(@RequestBody @Validated OrderDeductDTO dto) {