车辆实时计费

This commit is contained in:
yanglei 2025-12-26 14:40:31 +08:00
parent bcd0a46d87
commit 304aed9f8b
4 changed files with 122 additions and 6 deletions

View File

@ -6,11 +6,11 @@ import com.cdzy.user.model.dto.EbikeUserCyclingDto;
import com.cdzy.user.model.dto.EbikeUserCyclingEndDto;
import com.cdzy.user.model.entity.EbikeOrder;
import com.cdzy.user.model.vo.EbikeBikeInfoVo;
import com.cdzy.user.model.vo.EbikeBikeRealInfoVo;
import com.cdzy.user.model.vo.EbikeRevenueStatisticsVo;
import com.cdzy.user.model.vo.EbikeUserAllOrdersVo;
import com.cdzy.user.service.EbikeOrderService;
import com.ebike.feign.model.dto.FeignEbikeDto;
import com.ebike.feign.model.dto.FeignEbikeUserBikeInfo;
import com.ebike.feign.model.vo.FeignEbikeBikeRadiusVo;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
@ -131,4 +131,15 @@ public class EbikeOrderController {
List<EbikeRevenueStatisticsVo> revenueStatistics = ebikeOrderService.getRevenueStatistics();
return JsonResult.success(revenueStatistics);
}
/**
* 查询车辆实时信息
*
* @return 车辆实时信息
*/
@GetMapping("getBikeRealTimeInfo")
public JsonResult<?> getBikeRealTimeInfo(@RequestParam("orderId") Long orderId) {
EbikeBikeRealInfoVo revenueStatistics = ebikeOrderService.getBikeRealTimeInfo(orderId);
return JsonResult.success(revenueStatistics);
}
}

View File

@ -0,0 +1,26 @@
package com.cdzy.user.model.vo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 车辆实时信息
*
* @author yanglei
* @since 2025-12-26 11:03
*/
@Data
public class EbikeBikeRealInfoVo implements Serializable {
/**
* 当前费用
*/
private BigDecimal cost;
/**
* 车辆可用里程
*/
private Long mileage;
}

View File

@ -5,10 +5,10 @@ import com.cdzy.user.model.dto.EbikeUserCyclingDto;
import com.cdzy.user.model.dto.EbikeUserCyclingEndDto;
import com.cdzy.user.model.entity.EbikeOrder;
import com.cdzy.user.model.vo.EbikeBikeInfoVo;
import com.cdzy.user.model.vo.EbikeBikeRealInfoVo;
import com.cdzy.user.model.vo.EbikeRevenueStatisticsVo;
import com.cdzy.user.model.vo.EbikeUserAllOrdersVo;
import com.ebike.feign.model.dto.FeignEbikeDto;
import com.ebike.feign.model.dto.FeignEbikeUserBikeInfo;
import com.ebike.feign.model.dto.FeignOrderPaymentDto;
import com.ebike.feign.model.vo.FeignEbikeBikeRadiusVo;
import com.mybatisflex.core.paginate.Page;
@ -128,4 +128,12 @@ public interface EbikeOrderService extends IService<EbikeOrder> {
* @return 营收统计
*/
List<EbikeRevenueStatisticsVo> getRevenueStatistics();
/**
* 查询车辆实时信息
*
* @param orderId 订单id
* @return 车辆实时信息
*/
EbikeBikeRealInfoVo getBikeRealTimeInfo(Long orderId);
}

View File

@ -13,6 +13,7 @@ import com.cdzy.user.model.entity.EbikeOrder;
import com.cdzy.user.model.entity.EbikeOrderDetail;
import com.cdzy.user.model.entity.EbikePayment;
import com.cdzy.user.model.vo.EbikeBikeInfoVo;
import com.cdzy.user.model.vo.EbikeBikeRealInfoVo;
import com.cdzy.user.model.vo.EbikeRevenueStatisticsVo;
import com.cdzy.user.model.vo.EbikeUserAllOrdersVo;
import com.cdzy.user.service.EbikeOrderDetailService;
@ -88,10 +89,10 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
}
}
// 校验用户是否已进行实名认证
boolean userIsVerify = ebikeUserRealInfoService.checkUserIsVerify(userId);
if (!userIsVerify) {
throw new EbikeException("请先完成实名认证");
}
// boolean userIsVerify = ebikeUserRealInfoService.checkUserIsVerify(userId);
// if (!userIsVerify) {
// throw new EbikeException("请先完成实名认证");
// }
EbikeBikeInfoVo bikeInfo = queryBikeInfo(orderDto.getBikeCode());
// 创建订单
EbikeOrder order = EbikeOrder.builder()
@ -326,6 +327,76 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
return list;
}
/**
* 计算订单当前实时费用
*/
@Override
public EbikeBikeRealInfoVo getBikeRealTimeInfo(Long orderId) {
QueryWrapper queryWrapper = QueryWrapper.create()
.select(
EBIKE_ORDER.ORDER_STATUS,
EBIKE_ORDER.START_TIME,
EBIKE_ORDER.FREE_DURATION_MINUTES,
EBIKE_ORDER.BASE_FEE,
EBIKE_ORDER.DURATION_FEE,
EBIKE_ORDER.MAX_FEE_AMOUNT,
EBIKE_ORDER.BIKE_CODE
)
.where(EBIKE_ORDER.ORDER_ID.eq(orderId));
EbikeOrder ebikeOrder = this.mapper.selectOneByQuery(queryWrapper);
if (Objects.isNull(ebikeOrder)) {
throw new EbikeException("当前订单不存在");
}
// 查询车辆信息
EbikeBikeInfoVo bikeInfo = queryBikeInfo(ebikeOrder.getBikeCode());
// 计算实时费用包含封顶
BigDecimal cost = calculateRealTimeCost(ebikeOrder, bikeInfo);
// 计算可用里程剩余电量 × 0.7 (公里)
Float soc = bikeInfo.getSoc();
long mileage = (long) Math.floor(Math.max(GlobalConstants.NUMBER_ZERO, soc * 0.7));
EbikeBikeRealInfoVo result = new EbikeBikeRealInfoVo();
result.setCost(cost);
result.setMileage(mileage);
return result;
}
/**
* 辅助方法计算订单当前实时费用含封顶金额限制
*/
private BigDecimal calculateRealTimeCost(EbikeOrder order, EbikeBikeInfoVo bikeInfo) {
LocalDateTime now = LocalDateTime.now();
Duration duration = Duration.between(order.getStartTime(), now);
long totalSeconds = duration.getSeconds();
int currentMinutes = (int) ((totalSeconds + 59) / 60);
Integer freeMinutes = bikeInfo.getFreeDurationMinutes();
if (freeMinutes == null) {
freeMinutes = 0;
}
if (currentMinutes <= freeMinutes) {
return BigDecimal.ZERO;
}
return computeTotalFee(bikeInfo, currentMinutes - freeMinutes);
}
private BigDecimal computeTotalFee(EbikeBikeInfoVo bikeInfo, int chargeableMinutes) {
BigDecimal baseFee = Objects.requireNonNullElse(bikeInfo.getBaseFee(), BigDecimal.ZERO);
BigDecimal durationFee = Objects.requireNonNullElse(bikeInfo.getDurationFee(), BigDecimal.ZERO);
BigDecimal totalFee = baseFee.add(durationFee.multiply(BigDecimal.valueOf(chargeableMinutes)))
.setScale(2, RoundingMode.HALF_UP);
BigDecimal maxFee = bikeInfo.getMaxFeeAmount();
if (maxFee != null && maxFee.compareTo(BigDecimal.ZERO) > 0 && totalFee.compareTo(maxFee) > 0) {
totalFee = maxFee;
}
return totalFee;
}
/**
* 计算增长率并格式化为百分比字符串
*