diff --git a/ebike-user/src/main/java/com/cdzy/user/controller/EbikeOrderController.java b/ebike-user/src/main/java/com/cdzy/user/controller/EbikeOrderController.java index 311a9e1..3af4d43 100644 --- a/ebike-user/src/main/java/com/cdzy/user/controller/EbikeOrderController.java +++ b/ebike-user/src/main/java/com/cdzy/user/controller/EbikeOrderController.java @@ -5,6 +5,7 @@ import com.cdzy.common.model.response.JsonResult; 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.EbikeRevenueStatisticsVo; import com.cdzy.user.model.vo.EbikeUserAllOrdersVo; import com.cdzy.user.service.EbikeOrderService; import com.ebike.feign.model.dto.FeignEbikeDto; @@ -120,4 +121,13 @@ public class EbikeOrderController { return JsonResult.success(userAllOrders); } + + /** + * 查询营收统计。 + */ + @GetMapping("getRevenueStatistics") + public JsonResult getRevenueStatistics() { + List revenueStatistics = ebikeOrderService.getRevenueStatistics(); + return JsonResult.success(revenueStatistics); + } } diff --git a/ebike-user/src/main/java/com/cdzy/user/mapper/EbikeOrderMapper.java b/ebike-user/src/main/java/com/cdzy/user/mapper/EbikeOrderMapper.java index 8865d93..2ed2959 100644 --- a/ebike-user/src/main/java/com/cdzy/user/mapper/EbikeOrderMapper.java +++ b/ebike-user/src/main/java/com/cdzy/user/mapper/EbikeOrderMapper.java @@ -1,8 +1,11 @@ package com.cdzy.user.mapper; import com.cdzy.user.model.entity.EbikeOrder; +import com.cdzy.user.model.vo.EbikeRevenueStatisticsVo; import com.mybatisflex.core.BaseMapper; +import java.util.List; + /** * 用户订单 映射层 * @@ -11,4 +14,11 @@ import com.mybatisflex.core.BaseMapper; */ public interface EbikeOrderMapper extends BaseMapper { + + /** + * 获取营收统计 + * + * @return 营收统计 + */ + List selectRevenueComparison(); } diff --git a/ebike-user/src/main/java/com/cdzy/user/model/dto/EbikeUserCyclingDto.java b/ebike-user/src/main/java/com/cdzy/user/model/dto/EbikeUserCyclingDto.java index 8035558..4afdc7c 100644 --- a/ebike-user/src/main/java/com/cdzy/user/model/dto/EbikeUserCyclingDto.java +++ b/ebike-user/src/main/java/com/cdzy/user/model/dto/EbikeUserCyclingDto.java @@ -39,6 +39,6 @@ public class EbikeUserCyclingDto { @Column(typeHandler = PGpointTypeHandler.class) @JsonSerialize(using = PGpointSerializer.class) @JsonDeserialize(using = PGpointDeserializer.class) - @NotNull(message = "骑行结束点不能为空") + @NotNull(message = "骑行开始点不能为空") private PGpoint startPoint; } diff --git a/ebike-user/src/main/java/com/cdzy/user/model/vo/EbikeRevenueStatisticsVo.java b/ebike-user/src/main/java/com/cdzy/user/model/vo/EbikeRevenueStatisticsVo.java new file mode 100644 index 0000000..a7878f1 --- /dev/null +++ b/ebike-user/src/main/java/com/cdzy/user/model/vo/EbikeRevenueStatisticsVo.java @@ -0,0 +1,65 @@ +package com.cdzy.user.model.vo; + +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 营收统计 + * + * @author yanglei + * @since 2025-11-28 09:21 + */ +@Data +public class EbikeRevenueStatisticsVo { + + /** + * 运营商ID + */ + private Long operatorId; + + /** + * 当日营收 + */ + private BigDecimal todayRevenue; + + /** + * 昨日营收 + */ + private BigDecimal yesterdayRevenue; + + /** + * 当日比昨日比率 + */ + private String todayGrowth; + + /** + * 这周营收 + */ + private BigDecimal thisWeekRevenue; + + /** + * 上周营收 + */ + private BigDecimal lastWeekRevenue; + + /** + * 这周比上周比率 + */ + private String weekGrowth; + + /** + * 这月营收 + */ + private BigDecimal thisMonthRevenue; + + /** + * 上月营收 + */ + private BigDecimal lastMonthRevenue; + + /** + * 这月比上月比率 + */ + private String monthGrowth; +} diff --git a/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java b/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java index 6aa1fcd..2139fe4 100644 --- a/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java +++ b/ebike-user/src/main/java/com/cdzy/user/service/EbikeOrderService.java @@ -4,6 +4,7 @@ import com.cdzy.common.model.request.PageParam; 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.EbikeRevenueStatisticsVo; import com.cdzy.user.model.vo.EbikeUserAllOrdersVo; import com.ebike.feign.model.dto.FeignEbikeDto; import com.ebike.feign.model.dto.FeignEbikeUserBikeInfo; @@ -119,4 +120,11 @@ public interface EbikeOrderService extends IService { * @return 用户订单 */ Page getUserAllOrder(Long userId, Integer orderStatus, PageParam page); + + /** + * 获取营收统计 + * + * @return 营收统计 + */ + List getRevenueStatistics(); } diff --git a/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderImpl.java b/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderImpl.java index c391abd..789c4bc 100644 --- a/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderImpl.java +++ b/ebike-user/src/main/java/com/cdzy/user/service/impl/EbikeOrderImpl.java @@ -12,6 +12,7 @@ import com.cdzy.user.model.dto.EbikeUserCyclingEndDto; 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.EbikeRevenueStatisticsVo; import com.cdzy.user.model.vo.EbikeUserAllOrdersVo; import com.cdzy.user.service.EbikeOrderDetailService; import com.cdzy.user.service.EbikeOrderService; @@ -33,6 +34,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; +import java.math.RoundingMode; import java.time.Duration; import java.time.LocalDateTime; import java.util.ArrayList; @@ -80,10 +82,12 @@ public class EbikeOrderImpl extends ServiceImpl im throw new EbikeException("请完成未支付订单后再试"); } } + FeignEbikeUserBikeInfo bikeInfo = queryBikeInfo(orderDto.getBikeCode()); // 创建订单 EbikeOrder order = EbikeOrder.builder() .userId(userId) .bikeCode(orderDto.getBikeCode()) + .operatorId(bikeInfo.getOperatorId()) .orderType(OrderType.ONCE) .startLocation(orderDto.getStartPoint()) .startTime(LocalDateTime.now()) @@ -214,9 +218,7 @@ public class EbikeOrderImpl extends ServiceImpl im order.setNoParkingZoneFee(bikeInfo.getNoParkingZoneFee()); order.setOutOfParkingAreaFee(bikeInfo.getOutOfParkingAreaFee()); order.setOutOfServiceAreaFee(bikeInfo.getOutOfServiceAreaFee()); - order.setNoParkingZoneFee(bikeInfo.getMaxFeeAmount()); - order.setOrderStatus(OrderStatus.PENDING_PAYMENT); - + order.setMaxFeeAmount(bikeInfo.getMaxFeeAmount()); // 关锁 JsonResult jsonResult = operationsFeignClient.lock(endDto.getBikeCode()); if (jsonResult.getCode() != Code.SUCCESS) { @@ -234,6 +236,7 @@ public class EbikeOrderImpl extends ServiceImpl im updateById(order); return order.getOrderId(); } + order.setOrderStatus(OrderStatus.PENDING_PAYMENT); order.setTotalAmount(totalAmount); order.setActualAmount(totalAmount); updateById(order); @@ -272,38 +275,58 @@ public class EbikeOrderImpl extends ServiceImpl im public Page getUserAllOrder(Long userId, Integer orderStatus, PageParam page) { QueryWrapper queryWrapper = QueryWrapper.create() .select( - EBIKE_ORDER.ORDER_ID, - EBIKE_REFUND.REFUND_ID, - EBIKE_ORDER.OPERATOR_ID, - EBIKE_ORDER.BIKE_CODE, - EBIKE_ORDER.ORDER_TYPE, - EBIKE_ORDER.ORDER_STATUS, - EBIKE_ORDER.TOTAL_AMOUNT, - EBIKE_ORDER.ACTUAL_AMOUNT, - EBIKE_ORDER.START_TIME, - EBIKE_ORDER.END_TIME, - EBIKE_ORDER.PAYMENT_TIME, - EBIKE_ORDER.PAYMENT_METHOD, - EBIKE_ORDER.BASE_FEE, - EBIKE_ORDER.DURATION_FEE, - EBIKE_ORDER.FREE_DURATION_MINUTES, - EBIKE_ORDER.CHARGE_DURATION_MINUTES, - EBIKE_ORDER.NO_PARKING_ZONE_FEE, - EBIKE_ORDER.OUT_OF_PARKING_AREA_FEE, - EBIKE_ORDER.OUT_OF_SERVICE_AREA_FEE, - EBIKE_ORDER.MAX_FEE_AMOUNT, - EBIKE_ORDER.HELMET_MANAGEMENT_FEE, - EBIKE_ORDER.START_LOCATION, - EBIKE_ORDER.END_LOCATION, - EBIKE_ORDER.CREATE_TIME + EBIKE_ORDER.ALL_COLUMNS, + EBIKE_REFUND.REFUND_ID ) .where(EBIKE_ORDER.USER_ID.eq(userId)) - .and(EBIKE_ORDER.ORDER_STATUS.eq(orderStatus,Objects.nonNull(orderStatus))) + .and(EBIKE_ORDER.ORDER_STATUS.eq(orderStatus, Objects.nonNull(orderStatus))) .leftJoin(EBIKE_REFUND).on(EBIKE_REFUND.ORDER_ID.eq(EBIKE_ORDER.ORDER_ID)); queryWrapper.orderBy(EBIKE_ORDER.CREATE_TIME.desc()); return this.mapper.paginateAs(page.getPage(), queryWrapper, EbikeUserAllOrdersVo.class); } + @Override + public List getRevenueStatistics() { + List list = this.mapper.selectRevenueComparison(); + + // 每个 operator 计算增长率 + for (EbikeRevenueStatisticsVo vo : list) { + vo.setTodayGrowth(formatGrowthRate(vo.getTodayRevenue(), vo.getYesterdayRevenue())); + vo.setWeekGrowth(formatGrowthRate(vo.getThisWeekRevenue(), vo.getLastWeekRevenue())); + vo.setMonthGrowth(formatGrowthRate(vo.getThisMonthRevenue(), vo.getLastMonthRevenue())); + } + + return list; + } + + /** + * 计算增长率并格式化为百分比字符串 + * + * @param current 当前周期营收 + * @param previous 上一周期营收 + * @return 格式化字符串,如 "13.64%"、"0.00%"、"∞" + */ + private String formatGrowthRate(BigDecimal current, BigDecimal previous) { + if (current == null) { + current = BigDecimal.ZERO; + } + if (previous == null) { + previous = BigDecimal.ZERO; + } + + // 若 previous 为 0,则视为 1 + BigDecimal denominator = previous.compareTo(BigDecimal.ZERO) == 0 + ? BigDecimal.ONE + : previous; + + // 计算增长率:(current - previous) / denominator * 100% + BigDecimal growth = current.subtract(previous) + .divide(denominator, 4, RoundingMode.HALF_UP) + .multiply(BigDecimal.valueOf(100)); + + return growth.setScale(2, RoundingMode.HALF_UP) + "%"; + } + private List buildOrderDetails(EbikeOrder order) { List details = new ArrayList<>(); diff --git a/ebike-user/src/main/resources/mapper/EbikeOrderMapper.xml b/ebike-user/src/main/resources/mapper/EbikeOrderMapper.xml new file mode 100644 index 0000000..3defbb2 --- /dev/null +++ b/ebike-user/src/main/resources/mapper/EbikeOrderMapper.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file