Bläddra i källkod

新增u店订单统计接口

zhangchen 1 vecka sedan
förälder
incheckning
82b3cc270c

+ 49 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/LifeUserOrderListWithStatisticsVO.java

@@ -0,0 +1,49 @@
+package shop.alien.entity.store.vo;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 订单列表及统计信息VO
+ *
+ * @author system
+ * @since 2025-01-XX
+ */
+@Data
+@ApiModel(value = "LifeUserOrderListWithStatisticsVO对象", description = "订单列表及统计信息VO")
+public class LifeUserOrderListWithStatisticsVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "订单列表")
+    private IPage<LifeUserOrderVo> orderList;
+
+    @ApiModelProperty(value = "待支付订单数量")
+    private Long waitPayCount;
+
+    @ApiModelProperty(value = "已支付/待使用订单数量")
+    private Long waitUseCount;
+
+    @ApiModelProperty(value = "已核销订单数量")
+    private Long usedCount;
+
+    @ApiModelProperty(value = "已过期订单数量")
+    private Long expireCount;
+
+    @ApiModelProperty(value = "已取消订单数量")
+    private Long cancelCount;
+
+    @ApiModelProperty(value = "已退款订单数量")
+    private Long refundCount;
+
+    @ApiModelProperty(value = "退款失败订单数量")
+    private Long refundFailedCount;
+
+    @ApiModelProperty(value = "已完成订单数量")
+    private Long completeCount;
+}
+

+ 39 - 0
alien-entity/src/main/java/shop/alien/mapper/LifeUserOrderMapper.java

@@ -130,6 +130,45 @@ public interface LifeUserOrderMapper extends BaseMapper<LifeUserOrder> {
     IPage<LifeUserOrderVo> queryUserOrderList(IPage<LifeUserOrderVo> brandedPage,@Param(Constants.WRAPPER) QueryWrapper<LifeUserOrderVo> lifeUserOrderQueryWrapper);
 
     /**
+     * 统计各状态订单数量
+     * <p>
+     * 注意:此查询需要与queryUserOrderList使用相同的查询条件,但不需要分页和分组
+     * </p>
+     *
+     * @param queryWrapper 查询条件包装器(需要移除分页和分组条件)
+     * @return 各状态订单数量统计,key为orderStatus(订单状态),value为orderCount(订单数量)
+     */
+    @Select("WITH total_coupon AS (\n" +
+            "    -- 团购\n" +
+            "    SELECT id coupon_id, 2 coupon_type, lgbm.group_name coupon_name, " +
+            "           SUBSTRING_INDEX(image_id, ',', 1) AS image_id, " +
+            "           effective_date_type, effective_date_value \n" +
+            "    FROM life_group_buy_main lgbm \n" +
+            "    UNION ALL\n" +
+            "    -- 代金券\n" +
+            "    SELECT id coupon_id, 1 coupon_type, lc.name coupon_name, " +
+            "           SUBSTRING_INDEX(image_path, ',', 1) AS image_id, " +
+            "           0 effective_date_type, expiration_date effective_date_value \n" +
+            "    FROM life_coupon lc \n" +
+            ")\n" +
+            "SELECT " +
+            "    ocm.status AS orderStatus, " +
+            "    COUNT(DISTINCT luo.id) AS orderCount " +
+            "FROM life_user_order luo " +
+            "LEFT JOIN store_info si ON si.id = luo.store_id " +
+            "LEFT JOIN life_user lu ON lu.id = luo.user_id AND lu.delete_flag = 0 " +
+            "LEFT JOIN order_coupon_middle ocm ON ocm.order_id = luo.id " +
+            "LEFT JOIN total_coupon tc ON tc.coupon_id = ocm.coupon_id AND tc.coupon_type = luo.coupon_type " +
+            "LEFT JOIN store_img simg ON simg.id = tc.image_id AND simg.delete_flag = 0 " +
+            "LEFT JOIN store_comment sc ON sc.business_id = luo.id AND sc.delete_flag = 0 AND sc.business_type = 5 " +
+            "LEFT JOIN life_discount_coupon_user ldcu ON ldcu.id = luo.quan_id " +
+            "LEFT JOIN life_discount_coupon ldc ON ldc.id = ldcu.coupon_id " +
+            "${ew.customSqlSegment} " +
+            "AND ocm.status IS NOT NULL " +
+            "GROUP BY luo.status")
+    List<Map<String, Object>> countOrdersByStatus(@Param(Constants.WRAPPER) QueryWrapper<LifeUserOrderVo> queryWrapper);
+
+    /**
      * 查询过期退款订单
      * @param selectWrapper
      * @return

+ 31 - 0
alien-store/src/main/java/shop/alien/store/controller/LifeUserOrderController.java

@@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.*;
 import shop.alien.entity.result.R;
 import shop.alien.entity.store.LifeRefundOrder;
 import shop.alien.entity.store.dto.LifeUserOrderDto;
+import shop.alien.entity.store.vo.LifeUserOrderListWithStatisticsVO;
 import shop.alien.entity.store.vo.LifeUserOrderVo;
 import shop.alien.store.service.LifeUserOrderService;
 
@@ -142,4 +143,34 @@ public class LifeUserOrderController {
         log.info("UserOrderController.getAvailableOrderNumByOrderNo?orderNo={}", orderNo);
         return R.data(lifeUserOrderService.getAvailableOrderNumByOrderNo(orderNo));
     }
+
+    @ApiOperation("查询订单列表-用户端(包含各状态订单数量统计)")
+    @ApiOperationSupport(order = 8)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "page", value = "当前页", required = true),
+            @ApiImplicitParam(name = "size", value = "每页数量", required = true),
+            @ApiImplicitParam(name = "userId", value = "用户id", required = false),
+            @ApiImplicitParam(name = "storeId", value = "商户id", required = false),
+            @ApiImplicitParam(name = "couponType", value = "订单类型,-1,全部(可以不传),1,代金券;2,团购;", required = false),
+            @ApiImplicitParam(name = "orderStatus", value = "订单状态,-1,全部(可以不传);1,已支付/待使用;2,已完成;5,退款/售后", required = false),
+            @ApiImplicitParam(name = "name", value = "订单名称", required = false)
+    })
+    @GetMapping("/queryUserOrderListWithStatistics")
+    public R<LifeUserOrderListWithStatisticsVO> queryUserOrderListWithStatistics(
+            @RequestParam(value = "page", defaultValue = "1") Integer page,
+            @RequestParam(value = "size", defaultValue = "10") Integer size,
+            @RequestParam(required = false) String userId,
+            @RequestParam(required = false) String storeId,
+            @RequestParam(required = false, defaultValue = "-1") String couponType,
+            @RequestParam(required = false, defaultValue = "-1") String orderStatus,
+            @RequestParam(required = false) String name,
+            @RequestParam(value = "startTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd 00:00:00") String startTime,
+            @RequestParam(value = "endTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd 23:59:59") String endTime) {
+        log.info("userOrder.queryUserOrderListWithStatistics:page={}&size={}&userId={}&storeId={}&orderType={}&orderStatus={}&name={}&startTime={}&endTime={}",
+                page, size, userId, storeId, couponType, orderStatus, name, startTime, endTime);
+        if (StringUtils.isNotBlank(userId) && StringUtils.isNotBlank(storeId)) {
+            return R.fail("用户id和商户id不能同时为空");
+        }
+        return R.data(lifeUserOrderService.queryUserOrderListWithStatistics(page, size, userId, storeId, couponType, orderStatus, name, startTime, endTime));
+    }
 }

+ 221 - 0
alien-store/src/main/java/shop/alien/store/service/LifeUserOrderService.java

@@ -19,6 +19,7 @@ import shop.alien.entity.store.*;
 import shop.alien.entity.store.dto.LifeUserOrderDto;
 import shop.alien.entity.store.excelVo.LifeUserOrderExcelVo;
 import shop.alien.entity.store.excelVo.util.ExcelGenerator;
+import shop.alien.entity.store.vo.LifeUserOrderListWithStatisticsVO;
 import shop.alien.entity.store.vo.LifeUserOrderVo;
 import shop.alien.entity.store.vo.StoreInfoVo;
 import shop.alien.entity.store.vo.WebSocketVo;
@@ -1002,6 +1003,226 @@ public class LifeUserOrderService extends ServiceImpl<LifeUserOrderMapper, LifeU
     }
 
     /**
+     * 全部订单类型标识
+     */
+    private static final String ALL_COUPON_TYPE = "-1";
+
+    /**
+     * 删除标记:未删除
+     */
+    private static final Integer DELETE_FLAG_NOT_DELETED = 0;
+
+    /**
+     * 默认订单数量
+     */
+    private static final Long DEFAULT_ORDER_COUNT = 0L;
+
+    /**
+     * Map key:订单状态
+     */
+    private static final String KEY_ORDER_STATUS = "orderStatus";
+
+    /**
+     * Map key:订单数量
+     */
+    private static final String KEY_ORDER_COUNT = "orderCount";
+
+    /**
+     * 时间格式后缀:开始时间
+     */
+    private static final String TIME_START_SUFFIX = " 00:00:00";
+
+    /**
+     * 时间格式后缀:结束时间
+     */
+    private static final String TIME_END_SUFFIX = " 23:59:59";
+
+    /**
+     * 查询用户订单列表(包含各状态订单数量统计)
+     *
+     * @param page        页码
+     * @param size        每页数量
+     * @param userId      用户id
+     * @param storeId     商户id
+     * @param couponType  订单类型
+     * @param orderStatus 订单状态
+     * @param name        订单名称
+     * @param startTime   开始时间
+     * @param endTime     结束时间
+     * @return 订单列表及统计信息
+     */
+    public LifeUserOrderListWithStatisticsVO queryUserOrderListWithStatistics(
+            Integer page, Integer size, String userId, String storeId, String couponType,
+            String orderStatus, String name, String startTime, String endTime) {
+        // 查询订单列表
+        IPage<LifeUserOrderVo> orderList = queryUserOrderList(page, size, userId, storeId,
+                couponType, orderStatus, name, startTime, endTime);
+
+        // 构建统计查询条件
+        QueryWrapper<LifeUserOrderVo> statisticsQueryWrapper = buildStatisticsQueryWrapper(
+                userId, storeId, couponType, name, startTime, endTime);
+
+        // 统计各状态订单数量
+        List<Map<String, Object>> statusCountList = lifeUserOrderMapper.countOrdersByStatus(statisticsQueryWrapper);
+
+        // 构建返回结果
+        LifeUserOrderListWithStatisticsVO result = new LifeUserOrderListWithStatisticsVO();
+        result.setOrderList(orderList);
+
+        // 初始化各状态订单数量
+        initializeStatusCounts(result);
+
+        // 填充各状态订单数量
+        fillStatusCounts(result, statusCountList);
+
+        return result;
+    }
+
+    /**
+     * 构建统计查询条件
+     * <p>
+     * 与列表查询条件相同,但不包含状态筛选、分页和分组
+     * </p>
+     *
+     * @param userId     用户id
+     * @param storeId    商户id
+     * @param couponType 订单类型
+     * @param name       订单名称
+     * @param startTime  开始时间
+     * @param endTime    结束时间
+     * @return 查询条件包装器
+     */
+    private QueryWrapper<LifeUserOrderVo> buildStatisticsQueryWrapper(String userId, String storeId,
+                                                                      String couponType, String name,
+                                                                      String startTime, String endTime) {
+        QueryWrapper<LifeUserOrderVo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq(org.apache.commons.lang3.StringUtils.isNotBlank(userId), "luo.user_id", userId);
+        queryWrapper.eq(org.apache.commons.lang3.StringUtils.isNotBlank(storeId), "luo.store_id", storeId);
+        queryWrapper.eq(null != couponType && !ALL_COUPON_TYPE.equals(couponType), "luo.coupon_type", couponType);
+        queryWrapper.like(org.apache.commons.lang3.StringUtils.isNotBlank(name), "tc.coupon_name", name);
+        queryWrapper.gt(org.apache.commons.lang3.StringUtils.isNotBlank(startTime),
+                "luo.created_time", startTime + TIME_START_SUFFIX);
+        queryWrapper.lt(org.apache.commons.lang3.StringUtils.isNotBlank(endTime),
+                "luo.created_time", endTime + TIME_END_SUFFIX);
+        queryWrapper.eq("luo.delete_flag", DELETE_FLAG_NOT_DELETED);
+        return queryWrapper;
+    }
+
+    /**
+     * 初始化各状态订单数量为0
+     *
+     * @param result 结果对象
+     */
+    private void initializeStatusCounts(LifeUserOrderListWithStatisticsVO result) {
+        result.setWaitPayCount(DEFAULT_ORDER_COUNT);
+        result.setWaitUseCount(DEFAULT_ORDER_COUNT);
+        result.setUsedCount(DEFAULT_ORDER_COUNT);
+        result.setExpireCount(DEFAULT_ORDER_COUNT);
+        result.setCancelCount(DEFAULT_ORDER_COUNT);
+        result.setRefundCount(DEFAULT_ORDER_COUNT);
+        result.setRefundFailedCount(DEFAULT_ORDER_COUNT);
+        result.setCompleteCount(DEFAULT_ORDER_COUNT);
+    }
+
+    /**
+     * 填充各状态订单数量
+     *
+     * @param result          结果对象
+     * @param statusCountList 状态统计列表
+     */
+    private void fillStatusCounts(LifeUserOrderListWithStatisticsVO result,
+                                   List<Map<String, Object>> statusCountList) {
+        if (statusCountList == null || statusCountList.isEmpty()) {
+            return;
+        }
+
+        for (Map<String, Object> item : statusCountList) {
+            Integer status = getIntegerValue(item.get(KEY_ORDER_STATUS));
+            Long count = getLongValue(item.get(KEY_ORDER_COUNT));
+            if (status != null && count != null) {
+                setStatusCount(result, status, count);
+            }
+        }
+    }
+
+    /**
+     * 根据订单状态设置对应的数量
+     *
+     * @param result  结果对象
+     * @param status  订单状态
+     * @param count   订单数量
+     */
+    private void setStatusCount(LifeUserOrderListWithStatisticsVO result, Integer status, Long count) {
+        if (OrderStatusEnum.WAIT_PAY.getStatus().equals(status)) {
+            result.setWaitPayCount(count);
+        } else if (OrderStatusEnum.WAIT_USE.getStatus().equals(status)) {
+            result.setWaitUseCount(count);
+        } else if (OrderStatusEnum.USED.getStatus().equals(status)) {
+            result.setUsedCount(count);
+        } else if (OrderStatusEnum.EXPIRE.getStatus().equals(status)) {
+            result.setExpireCount(count);
+        } else if (OrderStatusEnum.CANCEL.getStatus().equals(status)) {
+            result.setCancelCount(count);
+        } else if (OrderStatusEnum.REFUND.getStatus().equals(status)) {
+            result.setRefundCount(count);
+        } else if (OrderStatusEnum.REFUND_FAILED.getStatus().equals(status)) {
+            result.setRefundFailedCount(count);
+        } else if (OrderStatusEnum.COMPLETE.getStatus().equals(status)) {
+            result.setCompleteCount(count);
+        }
+    }
+
+    /**
+     * 从Map中获取Integer值
+     * <p>
+     * 支持Integer、Long、Number类型的转换
+     * </p>
+     *
+     * @param value 对象值,可能为Integer、Long或其他Number类型
+     * @return Integer值,如果value为null或无法转换则返回null
+     */
+    private Integer getIntegerValue(Object value) {
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Integer) {
+            return (Integer) value;
+        }
+        if (value instanceof Long) {
+            return ((Long) value).intValue();
+        }
+        if (value instanceof Number) {
+            return ((Number) value).intValue();
+        }
+        return null;
+    }
+
+    /**
+     * 从Map中获取Long值
+     * <p>
+     * 支持Long、Integer、Number类型的转换
+     * </p>
+     *
+     * @param value 对象值,可能为Long、Integer或其他Number类型
+     * @return Long值,如果value为null或无法转换则返回null
+     */
+    private Long getLongValue(Object value) {
+        if (value == null) {
+            return null;
+        }
+        if (value instanceof Long) {
+            return (Long) value;
+        }
+        if (value instanceof Integer) {
+            return ((Integer) value).longValue();
+        }
+        if (value instanceof Number) {
+            return ((Number) value).longValue();
+        }
+        return null;
+    }
+
+    /**
      * 查询用户订单详情
      *
      * @param orderId