日/周/月营收统计
This commit is contained in:
parent
107b7eb94b
commit
148896c5a6
@ -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<EbikeRevenueStatisticsVo> revenueStatistics = ebikeOrderService.getRevenueStatistics();
|
||||
return JsonResult.success(revenueStatistics);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<EbikeOrder> {
|
||||
|
||||
/**
|
||||
* 获取营收统计
|
||||
*
|
||||
* @return 营收统计
|
||||
*/
|
||||
List<EbikeRevenueStatisticsVo> selectRevenueComparison();
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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<EbikeOrder> {
|
||||
* @return 用户订单
|
||||
*/
|
||||
Page<EbikeUserAllOrdersVo> getUserAllOrder(Long userId, Integer orderStatus, PageParam page);
|
||||
|
||||
/**
|
||||
* 获取营收统计
|
||||
*
|
||||
* @return 营收统计
|
||||
*/
|
||||
List<EbikeRevenueStatisticsVo> getRevenueStatistics();
|
||||
}
|
||||
|
||||
@ -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<EbikeOrderMapper, EbikeOrder> 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<EbikeOrderMapper, EbikeOrder> 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<FeignEbikeUserLockDto> jsonResult = operationsFeignClient.lock(endDto.getBikeCode());
|
||||
if (jsonResult.getCode() != Code.SUCCESS) {
|
||||
@ -234,6 +236,7 @@ public class EbikeOrderImpl extends ServiceImpl<EbikeOrderMapper, EbikeOrder> 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<EbikeOrderMapper, EbikeOrder> im
|
||||
public Page<EbikeUserAllOrdersVo> 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<EbikeRevenueStatisticsVo> getRevenueStatistics() {
|
||||
List<EbikeRevenueStatisticsVo> 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<EbikeOrderDetail> buildOrderDetails(EbikeOrder order) {
|
||||
List<EbikeOrderDetail> details = new ArrayList<>();
|
||||
|
||||
58
ebike-user/src/main/resources/mapper/EbikeOrderMapper.xml
Normal file
58
ebike-user/src/main/resources/mapper/EbikeOrderMapper.xml
Normal file
@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="com.cdzy.user.mapper.EbikeOrderMapper">
|
||||
|
||||
<resultMap id="EbikeRevenueStatisticsVoMap" type="com.cdzy.user.model.vo.EbikeRevenueStatisticsVo">
|
||||
<id column="operator_id" property="operatorId"/>
|
||||
<result column="today_revenue" property="todayRevenue" javaType="java.math.BigDecimal"/>
|
||||
<result column="yesterday_revenue" property="yesterdayRevenue" javaType="java.math.BigDecimal"/>
|
||||
<result column="this_week_revenue" property="thisWeekRevenue" javaType="java.math.BigDecimal"/>
|
||||
<result column="last_week_revenue" property="lastWeekRevenue" javaType="java.math.BigDecimal"/>
|
||||
<result column="this_month_revenue" property="thisMonthRevenue" javaType="java.math.BigDecimal"/>
|
||||
<result column="last_month_revenue" property="lastMonthRevenue" javaType="java.math.BigDecimal"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectRevenueComparison" resultMap="EbikeRevenueStatisticsVoMap">
|
||||
SELECT operator_id,
|
||||
COALESCE(SUM(CASE
|
||||
WHEN payment_time >= DATE_TRUNC('day', CURRENT_TIMESTAMP)
|
||||
AND payment_time < CURRENT_TIMESTAMP
|
||||
THEN actual_amount END), 0) AS today_revenue,
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
WHEN payment_time >= DATE_TRUNC('day', CURRENT_TIMESTAMP - INTERVAL '1 day')
|
||||
AND payment_time < DATE_TRUNC('day', CURRENT_TIMESTAMP)
|
||||
THEN actual_amount END), 0) AS yesterday_revenue,
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
WHEN payment_time >= DATE_TRUNC('week', CURRENT_TIMESTAMP)
|
||||
AND payment_time < CURRENT_TIMESTAMP
|
||||
THEN actual_amount END), 0) AS this_week_revenue,
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
WHEN payment_time >= DATE_TRUNC('week', CURRENT_TIMESTAMP - INTERVAL '7 days')
|
||||
AND payment_time < DATE_TRUNC('week', CURRENT_TIMESTAMP)
|
||||
THEN actual_amount END), 0) AS last_week_revenue,
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
WHEN payment_time >= DATE_TRUNC('month', CURRENT_TIMESTAMP)
|
||||
AND payment_time < CURRENT_TIMESTAMP
|
||||
THEN actual_amount END), 0) AS this_month_revenue,
|
||||
|
||||
COALESCE(SUM(CASE
|
||||
WHEN payment_time >= DATE_TRUNC('month', CURRENT_TIMESTAMP - INTERVAL '1 month')
|
||||
AND payment_time < DATE_TRUNC('month', CURRENT_TIMESTAMP)
|
||||
THEN actual_amount END), 0) AS last_month_revenue
|
||||
|
||||
FROM ebike_order
|
||||
WHERE order_status = 3
|
||||
AND payment_time IS NOT NULL
|
||||
AND is_deleted = false
|
||||
AND operator_id IS NOT NULL
|
||||
GROUP BY operator_id
|
||||
ORDER BY operator_id;
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Loading…
x
Reference in New Issue
Block a user